diff --git a/src/main/java/io/github/dsheirer/bits/BinaryMessage.java b/src/main/java/io/github/dsheirer/bits/BinaryMessage.java
index 68ed5a65..0539f7bd 100644
--- a/src/main/java/io/github/dsheirer/bits/BinaryMessage.java
+++ b/src/main/java/io/github/dsheirer/bits/BinaryMessage.java
@@ -243,6 +243,16 @@ public class BinaryMessage extends BitSet
return mSize;
}
+ /**
+ * Current size of the message indicating the quantity of bits that have been added to this message. This value
+ * is less than or equal to the size() value.
+ * @return current size in bits.
+ */
+ public int currentSize()
+ {
+ return mPointer;
+ }
+
public void setSize(int size)
{
mSize = size;
diff --git a/src/main/java/io/github/dsheirer/bits/IntField.java b/src/main/java/io/github/dsheirer/bits/IntField.java
index 4dc5dc91..3f6239a2 100644
--- a/src/main/java/io/github/dsheirer/bits/IntField.java
+++ b/src/main/java/io/github/dsheirer/bits/IntField.java
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
- * Copyright (C) 2014-2024 Dennis Sheirer
+ * Copyright (C) 2014-2025 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
@@ -69,6 +69,16 @@ public record IntField(int start, int end)
return new IntField(start, (start + 3));
}
+ /**
+ * Utility constructor method for a field with one four bits of length.
+ * @param start index (inclusive)
+ * @return constructed bit field.
+ */
+ public static IntField length6(int start)
+ {
+ return new IntField(start, (start + 5));
+ }
+
/**
* Utility constructor method for a field with one octet of length.
* @param start index (inclusive)
diff --git a/src/main/java/io/github/dsheirer/bits/MultiSyncPatternMatcher.java b/src/main/java/io/github/dsheirer/bits/MultiSyncPatternMatcher.java
index e3a58008..78671db1 100644
--- a/src/main/java/io/github/dsheirer/bits/MultiSyncPatternMatcher.java
+++ b/src/main/java/io/github/dsheirer/bits/MultiSyncPatternMatcher.java
@@ -1,35 +1,31 @@
/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2025 Dennis Sheirer
*
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * 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
- * * *****************************************************************************
+ * 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.bits;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
+import java.util.ArrayList;
+import java.util.List;
import org.apache.commons.lang3.Validate;
import org.apache.commons.math3.util.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Multi-Sync pattern matcher. Accepts multiple sync detector objects for
* comparision against the incoming bit stream.
@@ -39,6 +35,7 @@ import java.util.List;
* of the Long.rotate methods will wrap the MSB around to the LSB and
* corrupt the matching value.
*/
+@Deprecated //remove after P25P2 decoder is updated
public class MultiSyncPatternMatcher
{
private final static Logger mLog = LoggerFactory.getLogger(MultiSyncPatternMatcher.class);
diff --git a/src/main/java/io/github/dsheirer/bits/SoftSyncDetector.java b/src/main/java/io/github/dsheirer/bits/SoftSyncDetector.java
index a5abee55..def50c71 100644
--- a/src/main/java/io/github/dsheirer/bits/SoftSyncDetector.java
+++ b/src/main/java/io/github/dsheirer/bits/SoftSyncDetector.java
@@ -1,23 +1,27 @@
-/*******************************************************************************
- * sdr-trunk
- * Copyright (C) 2014-2018 Dennis Sheirer
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2025 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.bits;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
import org.apache.commons.lang3.Validate;
+@Deprecated //Remove after P25P2 decoder is updated.
public class SoftSyncDetector implements ISyncProcessor
{
private ISyncDetectListener mListener;
diff --git a/src/main/java/io/github/dsheirer/dsp/filter/design/FilterViewer.java b/src/main/java/io/github/dsheirer/dsp/filter/design/FilterViewer.java
index 3771675c..698a03ab 100644
--- a/src/main/java/io/github/dsheirer/dsp/filter/design/FilterViewer.java
+++ b/src/main/java/io/github/dsheirer/dsp/filter/design/FilterViewer.java
@@ -20,6 +20,7 @@
package io.github.dsheirer.dsp.filter.design;
import io.github.dsheirer.dsp.filter.FilterFactory;
+import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
import io.github.dsheirer.dsp.window.WindowType;
import javafx.application.Application;
import javafx.scene.Scene;
@@ -61,7 +62,26 @@ public class FilterViewer extends Application
int filterLength = 31;
WindowType windowType = WindowType.BLACKMAN_HARRIS_7;
- float[] taps = FilterFactory.getHighPass(8000, 3000, filterLength, windowType);
+ FIRFilterSpecification specification = FIRFilterSpecification
+ .lowPassBuilder()
+ .sampleRate(12500)
+ .passBandCutoff(5200)
+ .passBandAmplitude(1.0).passBandRipple(0.01) //.01
+ .stopBandAmplitude(0.0).stopBandStart(6500) //6500
+ .stopBandRipple(0.01).build();
+
+ float[] taps = null;
+
+ try
+ {
+ taps = FilterFactory.getTaps(specification);
+ }
+ catch(Exception fde) //FilterDesignException
+ {
+ System.out.println("Error");
+ }
+
+ // float[] taps = FilterFactory.getHighPass(8000, 3000, filterLength, windowType);
// float[] taps = FilterFactory.getRootRaisedCosine(50000.0 / 4800.0, 20, 0.2f);
// taps = HilbertTransform.HALF_BAND_FILTER_47_TAP;
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedDemodulator.java b/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedDemodulator.java
deleted file mode 100644
index 08b30d52..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedDemodulator.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2024 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.dsp.filter.interpolator.Interpolator;
-import io.github.dsheirer.dsp.filter.interpolator.InterpolatorFactory;
-import io.github.dsheirer.dsp.psk.pll.CostasLoop;
-import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop;
-import io.github.dsheirer.dsp.symbol.Dibit;
-import io.github.dsheirer.sample.complex.Complex;
-import java.text.DecimalFormat;
-
-public class DQPSKDecisionDirectedDemodulator extends PSKDemodulator
-{
- protected DQPSKDecisionDirectedSymbolEvaluator mSymbolEvaluator = new DQPSKDecisionDirectedSymbolEvaluator();
- private Complex mPreviousPrecedingSample = new Complex(0, 0);
- private Complex mPreviousCurrentSample = new Complex(0, 0);
- private Complex mPrecedingSample = new Complex(0, 0);
- private Complex mCurrentSample = new Complex(0, 0);
- private Complex mPrecedingSymbol = new Complex(0, 0);
- protected Complex mCurrentSymbol = new Complex(0, 0);
-
- private final Interpolator mInterpolator = InterpolatorFactory.getInterpolator();
- private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("+#0.00000;-#0.00000");
- private float[] mI = new float[15];
- private float[] mQ = new float[15];
-
- /**
- * Decoder for Differential Quaternary Phase Shift Keying (DQPSK). This decoder uses both a Costas Loop (PLL) and
- * a decision-directed DQPSK symbol timing and phase error detector to automatically align to the incoming carrier
- * frequency and to adjust for any changes in symbol timing.
- *
- * This detector is optimized for constant amplitude DQPSK symbols like C4FM.
- *
- * @param phaseLockedLoop for tracking carrier frequency error
- * @param interpolatingSampleBuffer to hold samples for interpolating a symbol
- */
- public DQPSKDecisionDirectedDemodulator(IPhaseLockedLoop phaseLockedLoop, InterpolatingSampleBuffer interpolatingSampleBuffer)
- {
- super(interpolatingSampleBuffer, phaseLockedLoop);
- }
-
- @Override
- public void receive(float inphase, float quadrature)
- {
- super.receive(inphase, quadrature);
-
- System.arraycopy(mI, 1, mI, 0, mI.length - 1);
- System.arraycopy(mQ, 1, mQ, 0, mQ.length - 1);
-
- //Rotate the sample and add to buffer
- Complex current = new Complex(inphase, quadrature);
- current.normalizeFast();
- current.multiply(getPLL().getCurrentVector());
- mI[mI.length - 1] = current.inphase();
- mQ[mQ.length - 1] = current.quadrature();
- float iTemp = mInterpolator.filter(mI, 6, .416f);
- float qTemp = mInterpolator.filter(mQ, 6, .416f);
- float iSymbol = (mI[0] * iTemp) - (-mQ[0] * qTemp);
- float qSymbol = (mI[0] * qTemp) + (iTemp * -mQ[0]);
- float radians = (float)Math.atan2(iSymbol, qSymbol);
-
- StringBuilder sb = new StringBuilder();
- sb.append(DECIMAL_FORMAT.format(radians)).append(",");
- sb.append(DECIMAL_FORMAT.format(((CostasLoop)getPLL()).getLoopFrequency()));
-// System.out.println(sb);
- }
-
- /**
- * Calculates a symbol from the interpolating buffer
- */
- protected void calculateSymbol()
- {
- //Get preceding sample and an interpolated current sample from the interpolating buffer
- mPrecedingSample = getInterpolatingSampleBuffer().getPrecedingSample();
- mCurrentSample = getInterpolatingSampleBuffer().getCurrentSample();
-
- //Differential decode preceding and current symbols by calculating the angular rotation between the previous and
- //current samples (current sample x complex conjugate of previous sample).
-
- //Note: preceding symbol is a preceding measurement of the current symbol that is simply used as a reference
- //point to determine vector rotation to the current symbol -- it is not the true predecessor symbol
- mPrecedingSymbol.setInphase(Complex.multiplyInphase(mPrecedingSample.inphase(), mPrecedingSample.quadrature(),
- mPreviousPrecedingSample.inphase(), -mPreviousPrecedingSample.quadrature()));
- mPrecedingSymbol.setQuadrature(Complex.multiplyQuadrature(mPrecedingSample.inphase(), mPrecedingSample.quadrature(),
- mPreviousPrecedingSample.inphase(), -mPreviousPrecedingSample.quadrature()));
-
- mCurrentSymbol.setInphase(Complex.multiplyInphase(mCurrentSample.inphase(), mCurrentSample.quadrature(),
- mPreviousCurrentSample.inphase(), -mPreviousCurrentSample.quadrature()));
- mCurrentSymbol.setQuadrature(Complex.multiplyQuadrature(mCurrentSample.inphase(), mCurrentSample.quadrature(),
- mPreviousCurrentSample.inphase(), -mPreviousCurrentSample.quadrature()));
-
- //Set gain to unity before we calculate the error value
- mPrecedingSymbol.normalize();
- mCurrentSymbol.normalize();
-
- //Apply symbols to evaluator to calculate phase and timing error and make a symbol decision
- mSymbolEvaluator.setSymbol(mPrecedingSymbol, mCurrentSymbol);
-
- //Update the symbol timing error
- getInterpolatingSampleBuffer().resetAndAdjust(mSymbolEvaluator.getTimingError());
-
- //Update the costas loop (PLL) with any measured phase error
-// getPLL().adjust(clip(mSymbolEvaluator.getPhaseError(), 0.5f));
-
- //Store current samples/symbols to use for the next symbol period
- mPreviousPrecedingSample.setValues(mPrecedingSample);
- mPreviousCurrentSample.setValues(mCurrentSample);
-
- broadcast(mSymbolEvaluator.getSymbolDecision());
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedDemodulatorInstrumented.java b/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedDemodulatorInstrumented.java
deleted file mode 100644
index 21f056f7..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedDemodulatorInstrumented.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.dsp.psk.pll.CostasLoop;
-import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.Complex;
-import io.github.dsheirer.sample.complex.ComplexSamples;
-import org.apache.commons.math3.util.FastMath;
-
-public class DQPSKDecisionDirectedDemodulatorInstrumented extends DQPSKDecisionDirectedDemodulator
-{
- private Listener mSymbolDecisionDataListener;
- private Listener mSamplesPerSymbolListener;
- private Listener mComplexSymbolListener;
- private Listener mPLLErrorListener;
- private Listener mPLLFrequencyListener;
- private Listener mFilteredGainAppliedComplexBufferListener;
- private double mSampleRate;
-
- /**
- * Decoder for Differential Quaternary Phase Shift Keying (DQPSK). This decoder uses both a Costas Loop (PLL) and
- * a custom DQPSK symbol timing error detector to automatically align to the incoming carrier frequency and to
- * adjust for any changes in symbol timing.
- *
- * This detector is optimized for constant amplitude DQPSK symbols like C4FM.
- *
- * @param phaseLockedLoop for tracking carrier frequency error
- * @param interpolatingSampleBuffer
- * @param sampleRate of the incoming complex sample stream
- */
- public DQPSKDecisionDirectedDemodulatorInstrumented(IPhaseLockedLoop phaseLockedLoop,
- InterpolatingSampleBufferInstrumented interpolatingSampleBuffer,
- double sampleRate)
- {
- super(phaseLockedLoop, interpolatingSampleBuffer);
- mSampleRate = sampleRate;
- }
-
- @Override
- public void receive(ComplexSamples complexSamples)
- {
- if(mFilteredGainAppliedComplexBufferListener != null)
- {
- mFilteredGainAppliedComplexBufferListener.receive(complexSamples);
- }
-
- super.receive(complexSamples);
- }
-
- /**
- * Overrides the parent class symbol calculation to capture eye diagram data
- */
- protected void calculateSymbol()
- {
- //Eye diagram listener
- if(mSymbolDecisionDataListener != null)
- {
- mSymbolDecisionDataListener.receive(
- ((InterpolatingSampleBufferInstrumented)getInterpolatingSampleBuffer()).getSymbolDecisionData());
- }
-
- super.calculateSymbol();
-
- if(mSamplesPerSymbolListener != null)
- {
- mSamplesPerSymbolListener.receive((double)getInterpolatingSampleBuffer().getSamplingPoint());
- }
-
- //Send to an external constellation symbol listener when registered
- if(mComplexSymbolListener != null)
- {
- mComplexSymbolListener.receive(mCurrentSymbol);
- }
-
- if(mPLLErrorListener != null)
- {
- mPLLErrorListener.receive((double)mSymbolEvaluator.getPhaseError());
- }
-
- if(mPLLFrequencyListener != null)
- {
- double loopFrequency = ((CostasLoop)getPLL()).getLoopFrequency();
-
- loopFrequency *= mSampleRate / (2.0 * FastMath.PI);
-
- mPLLFrequencyListener.receive(loopFrequency);
- }
- }
-
- /**
- * Registers a listener to receive symbol decision data to produce an eye diagram.
- */
- public void setSymbolDecisionDataListener(Listener listener)
- {
- mSymbolDecisionDataListener = listener;
- }
-
- /**
- * Registers the listener to receive PLL error values
- */
- public void setSamplesPerSymbolListener(Listener listener)
- {
- mSamplesPerSymbolListener = listener;
- }
-
- /**
- * Registers the listener to receive decoded QPSK symbols
- */
- public void setComplexSymbolListener(Listener listener)
- {
- mComplexSymbolListener = listener;
- }
-
- /**
- * Registers the listener to receive PLL error values
- */
- public void setPLLErrorListener(Listener listener)
- {
- mPLLErrorListener = listener;
- }
-
- /**
- * Registers the listener to receive PLL error values
- */
- public void setPLLFrequencyListener(Listener listener)
- {
- mPLLFrequencyListener = listener;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedSymbolEvaluator.java b/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedSymbolEvaluator.java
deleted file mode 100644
index 35a08c2d..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedSymbolEvaluator.java
+++ /dev/null
@@ -1,172 +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.dsp.symbol.Dibit;
-import io.github.dsheirer.sample.complex.Complex;
-import org.apache.commons.math3.util.FastMath;
-
-public class DQPSKDecisionDirectedSymbolEvaluator implements IPSKSymbolEvaluator
-{
- private static final Complex ROTATE_FROM_PLUS_135 = Complex.fromAngle(-3.0 * FastMath.PI / 4.0);
- private static final Complex ROTATE_FROM_PLUS_45 = Complex.fromAngle(-1.0 * FastMath.PI / 4.0);
- private static final Complex ROTATE_FROM_MINUS_45 = Complex.fromAngle(1.0 * FastMath.PI / 4.0);
- private static final Complex ROTATE_FROM_MINUS_135 = Complex.fromAngle(3.0 * FastMath.PI / 4.0);
-
- private Complex mEvaluationSymbol = new Complex(0, 0);
- private float mPhaseError = 0.0f;
- private float mTimingError = 0.0f;
- private float mTimingErrorPolarity = 1.0f;
- private Dibit mSymbolDecision = Dibit.D00_PLUS_1;
-
- /**
- * Differential QPSK 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.
- *
- * Phase and timing error are calculated as the angular distance of the sampled symbol from the reference
- * symbol. Timing error is further corrected to compensate for clock-wise or counter-clock-wise vector rotation
- * relative to the immediately preceding symbol.
- */
- public DQPSKDecisionDirectedSymbolEvaluator()
- {
- }
-
- /**
- * Sets the preceding and current symbols to be evaluated for phase and timing errors and to determine the
- * transmitted symbol relative to the closest reference symbol. After invoking this method, you can access the
- * phase and timing errors and the symbol decision via their respective accessor methods.
- *
- * Phase and timing error values are calculated by first determining the symbol and then calculating the phase
- * and timing errors relative to the reference symbol. The timing error is corrected with the appropriate sign
- * relative to the angular vector rotation so that the error value indicates the correct error direction.
- *
- * @param preceding differential-decoded sample/symbol used to detect rotation - does NOT need to be interpolated
- * since it's only a reference
- * @param current symbol to be evaluated - interpolated
- */
- public void setSymbol(Complex preceding, Complex current)
- {
- mEvaluationSymbol.setValues(current);
-
- if(mEvaluationSymbol.quadrature() > 0.0f)
- {
- if(mEvaluationSymbol.inphase() > 0.0f)
- {
- mSymbolDecision = Dibit.D00_PLUS_1;
- mTimingErrorPolarity = (preceding.quadrature() > current.quadrature() ? 1.0f : -1.0f);
- mEvaluationSymbol.multiply(ROTATE_FROM_PLUS_45);
- }
- else
- {
- mSymbolDecision = Dibit.D01_PLUS_3;
- mTimingErrorPolarity = (preceding.quadrature() < current.quadrature() ? 1.0f : -1.0f);
- mEvaluationSymbol.multiply(ROTATE_FROM_PLUS_135);
- }
-
- }
- else
- {
- if(mEvaluationSymbol.inphase() > 0.0f)
- {
- mSymbolDecision = Dibit.D10_MINUS_1;
- mTimingErrorPolarity = (preceding.quadrature() > current.quadrature() ? 1.0f : -1.0f);
- mEvaluationSymbol.multiply(ROTATE_FROM_MINUS_45);
- }
- else
- {
- mSymbolDecision = Dibit.D11_MINUS_3;
- mTimingErrorPolarity = (preceding.quadrature() < current.quadrature() ? 1.0f : -1.0f);
- mEvaluationSymbol.multiply(ROTATE_FROM_MINUS_135);
- }
- }
-
- //Since we've rotated the error symbol back to 0 radians, the quadrature value closely approximates the
- //arctan of the error angle relative to 0 radians and this provides our error value
- float errorNormalized = normalize(mEvaluationSymbol.quadrature(), 0.3f);
-
- mPhaseError = -errorNormalized;
-
- //Timing error is the same as phase error with the sign corrected according to the vector's angular rotation
- mTimingError = errorNormalized * mTimingErrorPolarity;
- }
-
- /**
- * Constrains value to the range of ( -maximum <> maximum )
- */
- private static float clip(float value, float maximum)
- {
- if(value > maximum)
- {
- return maximum;
- }
- else if(value < -maximum)
- {
- return -maximum;
- }
-
- return value;
- }
-
- /**
- * Constrains timing error to +/- the maximum value and corrects any
- * floating point invalid numbers
- */
- private float normalize(float error, float maximum)
- {
- if(Float.isNaN(error))
- {
- return 0.0f;
- }
- else
- {
- return clip(error, maximum);
- }
- }
-
- /**
- * Phase error of the symbol relative to the nearest reference symbol.
- *
- * @return phase error in radians of distance from the reference symbol.
- */
- @Override
- public float getPhaseError()
- {
- return mPhaseError;
- }
-
- /**
- * Timing error of the symbol relative to the nearest reference symbol.
- *
- * @return timing error in radians of angular distance from the reference symbol recognizing that the symbol
- * originates at zero radians and rotates toward the intended reference symbol, therefore the error value indicates
- * if the symbol was sampled early (-) or late (+) relative to the reference symbol.
- */
- @Override
- public float getTimingError()
- {
- return mTimingError;
- }
-
- /**
- * Reference symbol that is closest to the transmitted/sampled symbol.
- */
- @Override
- public Dibit getSymbolDecision()
- {
- return mSymbolDecision;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKGardnerDemodulatorInstrumented.java b/src/main/java/io/github/dsheirer/dsp/psk/DQPSKGardnerDemodulatorInstrumented.java
deleted file mode 100644
index 9f6df37a..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKGardnerDemodulatorInstrumented.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.dsp.psk.pll.CostasLoop;
-import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.Complex;
-import io.github.dsheirer.sample.complex.ComplexSamples;
-import org.apache.commons.math3.util.FastMath;
-
-public class DQPSKGardnerDemodulatorInstrumented extends DQPSKGardnerDemodulator
-{
- private Listener mSymbolDecisionDataListener;
- private Listener mSamplesPerSymbolListener;
- private Listener mComplexSymbolListener;
- private Listener mPLLErrorListener;
- private Listener mPLLFrequencyListener;
- private Listener mFilteredGainAppliedComplexBufferListener;
- private double mSampleRate;
-
- /**
- * Implements a Differential QPSK demodulator using a Costas Loop (PLL) and a Gardner timing error detector.
- *
- * This decoder is optimized for P25 Linear Simulcast Modulation (LSM).
- *
- * @param phaseLockedLoop for tracking carrier frequency error
- * @param interpolatingSampleBuffer to hold samples for interpolating a symbol
- */
- public DQPSKGardnerDemodulatorInstrumented(IPhaseLockedLoop phaseLockedLoop,
- InterpolatingSampleBuffer interpolatingSampleBuffer,
- double sampleRate)
- {
- super(phaseLockedLoop, interpolatingSampleBuffer);
- mSampleRate = sampleRate;
- }
-
- @Override
- public void receive(ComplexSamples complexSamples)
- {
- if(mFilteredGainAppliedComplexBufferListener != null)
- {
- mFilteredGainAppliedComplexBufferListener.receive(complexSamples);
- }
-
- super.receive(complexSamples);
- }
-
- /**
- * Overrides the parent class symbol calculation to capture eye diagram data
- */
- protected void calculateSymbol()
- {
- //Eye diagram listener
- if(mSymbolDecisionDataListener != null)
- {
- mSymbolDecisionDataListener.receive(
- ((InterpolatingSampleBufferInstrumented)getInterpolatingSampleBuffer()).getSymbolDecisionData());
- }
-
- super.calculateSymbol();
-
- if(mSamplesPerSymbolListener != null)
- {
- mSamplesPerSymbolListener.receive((double)getInterpolatingSampleBuffer().getSamplingPoint());
- }
-
- //Send to an external constellation symbol listener when registered
- if(mComplexSymbolListener != null)
- {
- mComplexSymbolListener.receive(mCurrentSymbol);
- }
-
- if(mPLLErrorListener != null)
- {
- mPLLErrorListener.receive((double)mSymbolEvaluator.getPhaseError());
- }
-
- if(mPLLFrequencyListener != null)
- {
- double loopFrequency = ((CostasLoop)getPLL()).getLoopFrequency();
-
- loopFrequency *= mSampleRate / (2.0 * FastMath.PI);
-
- mPLLFrequencyListener.receive(loopFrequency);
- }
- }
-
- /**
- * Registers a listener to receive symbol decision data to produce an eye diagram.
- */
- public void setSymbolDecisionDataListener(Listener listener)
- {
- mSymbolDecisionDataListener = listener;
- }
-
- /**
- * Registers the listener to receive PLL error values
- */
- public void setSamplesPerSymbolListener(Listener listener)
- {
- mSamplesPerSymbolListener = listener;
- }
-
- /**
- * Registers the listener to receive decoded QPSK symbols
- */
- public void setComplexSymbolListener(Listener listener)
- {
- mComplexSymbolListener = listener;
- }
-
- /**
- * Registers the listener to receive PLL error values
- */
- public void setPLLErrorListener(Listener listener)
- {
- mPLLErrorListener = listener;
- }
-
- /**
- * Registers the listener to receive PLL error values
- */
- public void setPLLFrequencyListener(Listener listener)
- {
- mPLLFrequencyListener = listener;
- }
-
- /**
- * Registers the listener to receive complex sample buffers that have been filtered with automatic gain control applied
- */
- public void setFilteredGainAppliedComplexBufferListener(Listener listener)
- {
- mFilteredGainAppliedComplexBufferListener = listener;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/GardnerDetector.java b/src/main/java/io/github/dsheirer/dsp/psk/GardnerDetector.java
deleted file mode 100644
index af0197de..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/GardnerDetector.java
+++ /dev/null
@@ -1,83 +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;
-import org.apache.commons.math3.util.FastMath;
-
-public class GardnerDetector
-{
- private float mErrorInphase;
- private float mErrorQuadrature;
- private float mError;
-
- /**
- * Gardner detector for recovering symbol timing error.
- */
- public GardnerDetector()
- {
- }
-
-
- /**
- * Calculates the symbol timing error by evaluating the previous, middle and current symbol instants.
- *
- * @param previous symbol
- * @param middle symbol (ie midway between the previous and current)
- * @param current symbol
- * @return symbol timing error
- */
- public float getError(Complex previous, Complex middle, Complex current)
- {
- mErrorInphase = (FastMath.abs(previous.inphase()) - FastMath.abs(current.inphase())) * FastMath.abs(middle.inphase());
- mErrorQuadrature = (FastMath.abs(previous.quadrature()) - FastMath.abs(current.quadrature())) * FastMath.abs(middle.quadrature());
- mError = normalize(mErrorInphase + mErrorQuadrature, 1.0f);
-
- return mError;
- }
-
- /**
- * Constrains timing error to +/- the maximum value and corrects any floating point invalid numbers
- */
- public static float normalize(float error, float maximum)
- {
- if(Float.isNaN(error))
- {
- return 0.0f;
- }
- else
- {
- return clip(error, maximum);
- }
- }
-
- /**
- * Constrains value to the range of ( -maximum <> maximum )
- */
- public static float clip(float value, float maximum)
- {
- if(value > maximum)
- {
- return maximum;
- }
- else if(value < -maximum)
- {
- return -maximum;
- }
-
- return value;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/IQPSKSymbolDecoder.java b/src/main/java/io/github/dsheirer/dsp/psk/IQPSKSymbolDecoder.java
deleted file mode 100644
index 0befad75..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/IQPSKSymbolDecoder.java
+++ /dev/null
@@ -1,29 +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.dsp.symbol.Dibit;
-import io.github.dsheirer.sample.complex.Complex;
-
-public interface IQPSKSymbolDecoder
-{
- /**
- * Decodes the symbol and converts it into a Dibit
- * @param symbol to decode
- * @return decoded dibit
- */
- Dibit decode(Complex symbol);
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/ISymbolPhaseErrorCalculator.java b/src/main/java/io/github/dsheirer/dsp/psk/ISymbolPhaseErrorCalculator.java
deleted file mode 100644
index 4e413d88..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/ISymbolPhaseErrorCalculator.java
+++ /dev/null
@@ -1,28 +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 interface ISymbolPhaseErrorCalculator
-{
- /**
- * Calculates the phase error of the symbol relative to an alignment for the constellation
- * @param symbol to calculate error
- * @return error value
- */
- float getPhaseError(Complex symbol);
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/InterpolatingSampleBufferInstrumented.java b/src/main/java/io/github/dsheirer/dsp/psk/InterpolatingSampleBufferInstrumented.java
deleted file mode 100644
index ecb08166..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/InterpolatingSampleBufferInstrumented.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *
- * * ******************************************************************************
- * * Copyright (C) 2014-2019 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * 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;
-import io.github.dsheirer.sample.complex.ComplexSampleListener;
-import org.apache.commons.math3.util.FastMath;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class InterpolatingSampleBufferInstrumented extends InterpolatingSampleBuffer
-{
- private final static Logger mLog = LoggerFactory.getLogger(InterpolatingSampleBufferInstrumented.class);
- private SymbolDecisionData mSymbolDecisionData;
- private ComplexSampleListener mSampleListener;
- private int mBufferLength;
-
- public InterpolatingSampleBufferInstrumented(float samplesPerSymbol, float symbolTimingGain)
- {
- super(samplesPerSymbol, symbolTimingGain);
- mBufferLength = (int) FastMath.ceil(samplesPerSymbol);
- mSymbolDecisionData = new SymbolDecisionData(mBufferLength);
- }
-
- public void receive(Complex sample)
- {
- super.receive(sample);
- mSymbolDecisionData.receive(sample);
-
- if(mSampleListener != null)
- {
- mSampleListener.receive(sample.inphase(), sample.quadrature());
- }
- }
-
- /**
- * Contents of the interpolating buffer and the current buffer index and symbol decision offset. This data can
- * be used to support an external eye-diagram chart.
- * @return symbol decision data.
- */
- public SymbolDecisionData getSymbolDecisionData()
- {
- for(int x = mDelayLinePointer; x < mDelayLinePointer + mBufferLength; x++)
- {
- mSymbolDecisionData.receive(mDelayLineInphase[x], mDelayLineQuadrature[x]);
- }
-
- mSymbolDecisionData.setSamplingPoint(getSamplingPoint());
- return mSymbolDecisionData;
- }
-
- /**
- * Sets the listener to receive samples being sent to this buffer. Note: these samples have
- * already been corrected by the PLL, so this provides an ideal tap point for PLL corrected samples.
- * @param listener to receive samples.
- */
- public void setSampleListener(ComplexSampleListener listener)
- {
- mSampleListener = listener;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/LSMConstellationDecoder.java b/src/main/java/io/github/dsheirer/dsp/psk/LSMConstellationDecoder.java
deleted file mode 100644
index 7c500838..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/LSMConstellationDecoder.java
+++ /dev/null
@@ -1,28 +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.dsp.symbol.Dibit;
-import io.github.dsheirer.sample.complex.Complex;
-
-public class LSMConstellationDecoder implements IQPSKSymbolDecoder
-{
- @Override
- public Dibit decode(Complex symbol)
- {
- return null;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/QPSKStarSlicer.java b/src/main/java/io/github/dsheirer/dsp/psk/QPSKStarSlicer.java
deleted file mode 100644
index b8295145..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/QPSKStarSlicer.java
+++ /dev/null
@@ -1,73 +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.dsp.symbol.Dibit;
-import io.github.dsheirer.sample.Broadcaster;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.Complex;
-
-public class QPSKStarSlicer implements IQPSKSymbolDecoder, Listener
-{
- private Broadcaster mBroadcaster = new Broadcaster();
-
- /**
- * Slices a Complex sample representing a phase shifted symbol according to the following constellation pattern:
- *
- * 00 +3 | 01 +1
- * ------|------
- * 10 -1 | 11 -1
- */
- public QPSKStarSlicer()
- {
- }
-
- public void dispose()
- {
- mBroadcaster.dispose();
- mBroadcaster = null;
- }
-
- public void addListener(Listener listener)
- {
- mBroadcaster.addListener(listener);
- }
-
- public void removeListener(Listener listener)
- {
- mBroadcaster.removeListener(listener);
- }
-
- @Override
- public void receive(Complex sample)
- {
- mBroadcaster.broadcast(decode(sample));
- }
-
- @Override
- public Dibit decode(Complex sample)
- {
- if(sample.inphase() > 0)
- {
- return sample.quadrature() > 0 ? Dibit.D00_PLUS_1 : Dibit.D10_MINUS_1;
- }
- else
- {
- return sample.quadrature() > 0 ? Dibit.D01_PLUS_3 : Dibit.D11_MINUS_3;
- }
- }
-
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/QPSKSymbolDecoder.java b/src/main/java/io/github/dsheirer/dsp/psk/QPSKSymbolDecoder.java
deleted file mode 100644
index d4dcfa6a..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/QPSKSymbolDecoder.java
+++ /dev/null
@@ -1,91 +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.dsp.symbol.Dibit;
-import io.github.dsheirer.sample.Broadcaster;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.Complex;
-import org.apache.commons.math3.util.FastMath;
-
-public class QPSKSymbolDecoder implements Listener, IQPSKSymbolDecoder
-{
- private Broadcaster mBroadcaster = new Broadcaster();
-
- /**
- * Slices a ComplexSample representing a phase shifted symbol according to
- * the following constellation pattern:
- *
- * \ 00 /
- * \ /
- * 01 \/ 10
- * /\
- * / \
- * / 11 \
- */
- public QPSKSymbolDecoder()
- {
- }
-
- public void dispose()
- {
- mBroadcaster.dispose();
- mBroadcaster = null;
- }
-
- public void addListener( Listener listener )
- {
- mBroadcaster.addListener( listener );
- }
-
- public void removeListener( Listener listener )
- {
- mBroadcaster.removeListener( listener );
- }
-
- @Override
- public void receive( Complex complex )
- {
- mBroadcaster.broadcast( decode( complex ) );
- }
-
- public Dibit decode(Complex complex )
- {
- if( FastMath.abs( complex.inphase() ) > FastMath.abs( complex.quadrature() ) )
- {
- if( complex.inphase() > 0 )
- {
- return Dibit.D10_MINUS_1;
- }
- else
- {
- return Dibit.D01_PLUS_3;
- }
- }
- else
- {
- if( complex.quadrature() > 0 )
- {
- return Dibit.D00_PLUS_1;
- }
- else
- {
- return Dibit.D11_MINUS_3;
- }
- }
- }
-
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/QPSKSymbolPhaseErrorCalculator.java b/src/main/java/io/github/dsheirer/dsp/psk/QPSKSymbolPhaseErrorCalculator.java
deleted file mode 100644
index 0fe1d5f8..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/QPSKSymbolPhaseErrorCalculator.java
+++ /dev/null
@@ -1,58 +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;
-import org.apache.commons.math3.util.FastMath;
-
-/**
- * Calculates the phase error for a QPSK polar-orientation constellation
- */
-public class QPSKSymbolPhaseErrorCalculator implements ISymbolPhaseErrorCalculator
-{
- private float mPhaseError;
-
- @Override
- public float getPhaseError(Complex symbol)
- {
- mPhaseError = 0.0f;
-
- if(FastMath.abs(symbol.inphase()) > FastMath.abs(symbol.quadrature()))
- {
- if(symbol.inphase() > 0)
- {
- mPhaseError = -symbol.quadrature();
- }
- else
- {
- mPhaseError = symbol.quadrature();
- }
- }
- else
- {
- if(symbol.quadrature() > 0)
- {
- mPhaseError = symbol.inphase();
- }
- else
- {
- mPhaseError = -symbol.inphase();
- }
- }
-
- return mPhaseError;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/SymbolDecisionData.java b/src/main/java/io/github/dsheirer/dsp/psk/SymbolDecisionData.java
deleted file mode 100644
index 327fde75..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/SymbolDecisionData.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- *
- * * ******************************************************************************
- * * Copyright (C) 2014-2019 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * 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.buffer.ComplexCircularBuffer;
-import io.github.dsheirer.sample.complex.Complex;
-import org.apache.commons.math3.util.FastMath;
-
-public class SymbolDecisionData
-{
- //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(FastMath.PI / 4.0d);
-
- private ComplexCircularBuffer mBuffer;
- private float mSamplingPoint;
- private float mSamplesPerSymbol;
-
- /**
- * Circular buffer for capturing two symbols worth of sample data for use in instrumentation.
- * @param samplesPerSymbol to size the buffer
- */
- public SymbolDecisionData(float samplesPerSymbol)
- {
- mSamplesPerSymbol = samplesPerSymbol;
- mBuffer = new ComplexCircularBuffer(8);
- }
-
- /**
- * Stores the complex sample in the buffer
- */
- public void receive(float inphase, float quadrature)
- {
- mBuffer.put(new Complex(inphase, quadrature));
- }
-
- /**
- * Stores the complex sample in the buffer
- */
- public void receive(Complex complex)
- {
- mBuffer.put(complex.copy());
- }
-
- /**
- * Sets the fractional sampling point for the current symbol to use in interpolating the current symbol.
- */
- public void setSamplingPoint(float samplingPoint)
- {
- mSamplingPoint = samplingPoint;
- }
-
- /**
- * Fractional sampling point
- */
- public float getSamplingPoint()
- {
- return mSamplingPoint;
- }
-
- /**
- * Raw samples
- */
- public Complex[] getSamples()
- {
- return mBuffer.getAll();
- }
-
- public Complex[] getSamples(int length)
- {
- return mBuffer.get(length);
- }
-
- /**
- * Array of (FM) demodulated samples representing the current symbol where each current sample is demodulated against
- * the previous symbol's sample to produce the differential demodulated sample. Samples are in time order.
- *
- * Note: differential decoding is on an integral samples-per-symbol basis and does not use fractional interpolation.
- */
- public Complex[] getDemodulated()
- {
- Complex[] samples = mBuffer.getAll();
-
- int length = samples.length / 2;
-
- Complex[] demodulated = new Complex[length];
-
- for(int x = 0; x < samples.length / 2; x++)
- {
- Complex copy = samples[length + x].copy();
- copy.multiply(samples[x].conjugate());
- demodulated[x] = copy;
- }
-
- return demodulated;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/SymbolInversion.java b/src/main/java/io/github/dsheirer/dsp/psk/SymbolInversion.java
deleted file mode 100644
index 22d55f37..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/SymbolInversion.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 org.apache.commons.math3.util.FastMath;
-
-public enum SymbolInversion
-{
- DEGREES_90_PLUS(FastMath.PI / 2.0),
- DEGREES_90_MINUS(FastMath.PI / -2.0),
- DEGREES_180(FastMath.PI);
-
- private double mAngleRadians;
-
- SymbolInversion(double angleRadians)
- {
- mAngleRadians = angleRadians;
- }
-
- public double getError()
- {
- return mAngleRadians;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFactory.java b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFactory.java
index d8253de5..22aae9b9 100644
--- a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFactory.java
+++ b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFactory.java
@@ -22,34 +22,30 @@ package io.github.dsheirer.dsp.psk.demod;
import io.github.dsheirer.vector.calibrate.CalibrationManager;
import io.github.dsheirer.vector.calibrate.CalibrationType;
import io.github.dsheirer.vector.calibrate.Implementation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Factory for creating PSK differential demodulators
*/
public class DifferentialDemodulatorFactory
{
- private static final Logger mLog = LoggerFactory.getLogger(DifferentialDemodulatorFactory.class);
-
/**
- * Creates the optimal demodulator using calibration data to select the optimal implementation from scalar and
- * vector options, or defaults to the scalar implementation if the calibration wasn't executed.
+ * Creates the optimal float output demodulator using calibration data to select the optimal implementation from
+ * scalar and vector options, or defaults to the scalar implementation if the calibration wasn't executed.
* @param sampleRate in Hertz
* @param symbolRate in Hertz
* @return demodulator instance
*/
- public static DifferentialDemodulator getDemodulator(double sampleRate, int symbolRate)
+ public static DifferentialDemodulatorFloat getFloatDemodulator(double sampleRate, int symbolRate)
{
Implementation implementation = CalibrationManager.getInstance().getImplementation(CalibrationType.DIFFERENTIAL_DEMODULATOR);
return switch(implementation)
{
- case VECTOR_SIMD_64 -> new DifferentialDemodulatorVector64(sampleRate, symbolRate);
- case VECTOR_SIMD_128 -> new DifferentialDemodulatorVector128(sampleRate, symbolRate);
- case VECTOR_SIMD_256 -> new DifferentialDemodulatorVector256(sampleRate, symbolRate);
- case VECTOR_SIMD_512 -> new DifferentialDemodulatorVector512(sampleRate, symbolRate);
- default -> new DifferentialDemodulatorScalar(sampleRate, symbolRate); //Includes SCALAR case
+ case VECTOR_SIMD_64 -> new DifferentialDemodulatorFloatVector64(sampleRate, symbolRate);
+ case VECTOR_SIMD_128 -> new DifferentialDemodulatorFloatVector128(sampleRate, symbolRate);
+ case VECTOR_SIMD_256 -> new DifferentialDemodulatorFloatVector256(sampleRate, symbolRate);
+ case VECTOR_SIMD_512 -> new DifferentialDemodulatorFloatVector512(sampleRate, symbolRate);
+ default -> new DifferentialDemodulatorFloatScalar(sampleRate, symbolRate); //Includes SCALAR case
};
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulator.java b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloat.java
similarity index 87%
rename from src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulator.java
rename to src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloat.java
index 53f0ea88..142c6ed4 100644
--- a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulator.java
+++ b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloat.java
@@ -26,7 +26,7 @@ import io.github.dsheirer.dsp.fm.IDemodulator;
/**
* Differential demodulator base class
*/
-public abstract class DifferentialDemodulator implements IDemodulator
+public abstract class DifferentialDemodulatorFloat implements IDemodulator
{
private int mSymbolRate;
private float mSampleRate;
@@ -37,14 +37,14 @@ public abstract class DifferentialDemodulator implements IDemodulator
protected int mBufferOverlap;
protected int mInterpolationOffset;
protected final Interpolator mInterpolator = InterpolatorFactory.getInterpolator();
- private DifferentialDemodulatorScalar mScalar;
+ private DifferentialDemodulatorFloatScalar mScalar;
/**
* Constructor
* @param sampleRate in Hertz
* @param symbolRate symbols per second
*/
- public DifferentialDemodulator(double sampleRate, int symbolRate)
+ public DifferentialDemodulatorFloat(double sampleRate, int symbolRate)
{
mSampleRate = (float) sampleRate;
mSymbolRate = symbolRate;
@@ -64,11 +64,11 @@ public abstract class DifferentialDemodulator implements IDemodulator
* Scalar implementation for fallback when the sample buffer size is not compatible with the vector implementation.
* @return scalar implementation lazy instantiated when needed.
*/
- protected DifferentialDemodulatorScalar getScalarImplementation()
+ protected DifferentialDemodulatorFloatScalar getScalarImplementation()
{
if(mScalar == null)
{
- mScalar = new DifferentialDemodulatorScalar(mSampleRate, mSymbolRate);
+ mScalar = new DifferentialDemodulatorFloatScalar(mSampleRate, mSymbolRate);
}
return mScalar;
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorScalar.java b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatScalar.java
similarity index 94%
rename from src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorScalar.java
rename to src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatScalar.java
index 0781206a..ea8ad1bb 100644
--- a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorScalar.java
+++ b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatScalar.java
@@ -26,16 +26,16 @@ import org.slf4j.LoggerFactory;
/**
* Differential demodulator that uses scalar calculations for demodulating the sample stream.
*/
-public class DifferentialDemodulatorScalar extends DifferentialDemodulator
+public class DifferentialDemodulatorFloatScalar extends DifferentialDemodulatorFloat
{
- private static final Logger LOGGER = LoggerFactory.getLogger(DifferentialDemodulatorScalar.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(DifferentialDemodulatorFloatScalar.class);
/**
* Constructor
*
* @param symbolRate symbols per second
*/
- public DifferentialDemodulatorScalar(double sampleRate, int symbolRate)
+ public DifferentialDemodulatorFloatScalar(double sampleRate, int symbolRate)
{
super(sampleRate, symbolRate);
}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorVector128.java b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatVector128.java
similarity index 95%
rename from src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorVector128.java
rename to src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatVector128.java
index f98829ee..72a2103d 100644
--- a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorVector128.java
+++ b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatVector128.java
@@ -29,9 +29,9 @@ import org.slf4j.LoggerFactory;
/**
* Differential demodulator that uses Vector SIMD 128 calculations for demodulating the sample stream.
*/
-public class DifferentialDemodulatorVector128 extends DifferentialDemodulator
+public class DifferentialDemodulatorFloatVector128 extends DifferentialDemodulatorFloat
{
- private static final Logger LOGGER = LoggerFactory.getLogger(DifferentialDemodulatorVector128.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(DifferentialDemodulatorFloatVector128.class);
private static final VectorSpecies VECTOR_SPECIES = FloatVector.SPECIES_128;
/**
@@ -40,7 +40,7 @@ public class DifferentialDemodulatorVector128 extends DifferentialDemodulator
* @param sampleRate in Hertz
* @param symbolRate symbols per second
*/
- public DifferentialDemodulatorVector128(double sampleRate, int symbolRate)
+ public DifferentialDemodulatorFloatVector128(double sampleRate, int symbolRate)
{
super(sampleRate, symbolRate);
}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorVector256.java b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatVector256.java
similarity index 96%
rename from src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorVector256.java
rename to src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatVector256.java
index ab82190a..ef5bc6af 100644
--- a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorVector256.java
+++ b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatVector256.java
@@ -27,7 +27,7 @@ import jdk.incubator.vector.VectorSpecies;
/**
* Differential demodulator that uses Vector SIMD calculations for demodulating the sample stream.
*/
-public class DifferentialDemodulatorVector256 extends DifferentialDemodulator
+public class DifferentialDemodulatorFloatVector256 extends DifferentialDemodulatorFloat
{
private static final VectorSpecies VECTOR_SPECIES = FloatVector.SPECIES_256;
@@ -37,7 +37,7 @@ public class DifferentialDemodulatorVector256 extends DifferentialDemodulator
* @param sampleRate in Hertz
* @param symbolRate symbols per second
*/
- public DifferentialDemodulatorVector256(double sampleRate, int symbolRate)
+ public DifferentialDemodulatorFloatVector256(double sampleRate, int symbolRate)
{
super(sampleRate, symbolRate);
}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorVector512.java b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatVector512.java
similarity index 95%
rename from src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorVector512.java
rename to src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatVector512.java
index 8108b8d8..579bdea2 100644
--- a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorVector512.java
+++ b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatVector512.java
@@ -29,9 +29,9 @@ import org.slf4j.LoggerFactory;
/**
* Differential demodulator that uses Vector SIMD 512 calculations for demodulating the sample stream.
*/
-public class DifferentialDemodulatorVector512 extends DifferentialDemodulator
+public class DifferentialDemodulatorFloatVector512 extends DifferentialDemodulatorFloat
{
- private static final Logger LOGGER = LoggerFactory.getLogger(DifferentialDemodulatorVector512.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(DifferentialDemodulatorFloatVector512.class);
private static final VectorSpecies VECTOR_SPECIES = FloatVector.SPECIES_512;
/**
@@ -39,7 +39,7 @@ public class DifferentialDemodulatorVector512 extends DifferentialDemodulator
*
* @param symbolRate symbols per second
*/
- public DifferentialDemodulatorVector512(double sampleRate, int symbolRate)
+ public DifferentialDemodulatorFloatVector512(double sampleRate, int symbolRate)
{
super(sampleRate, symbolRate);
}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorVector64.java b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatVector64.java
similarity index 95%
rename from src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorVector64.java
rename to src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatVector64.java
index 983de06d..00d9e555 100644
--- a/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorVector64.java
+++ b/src/main/java/io/github/dsheirer/dsp/psk/demod/DifferentialDemodulatorFloatVector64.java
@@ -29,9 +29,9 @@ import org.slf4j.LoggerFactory;
/**
* Differential demodulator that uses Vector SIMD 64 calculations for demodulating the sample stream.
*/
-public class DifferentialDemodulatorVector64 extends DifferentialDemodulator
+public class DifferentialDemodulatorFloatVector64 extends DifferentialDemodulatorFloat
{
- private static final Logger LOGGER = LoggerFactory.getLogger(DifferentialDemodulatorVector64.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(DifferentialDemodulatorFloatVector64.class);
private static final VectorSpecies VECTOR_SPECIES = FloatVector.SPECIES_64;
/**
@@ -40,7 +40,7 @@ public class DifferentialDemodulatorVector64 extends DifferentialDemodulator
* @param sampleRate in Hertz
* @param symbolRate symbols per second
*/
- public DifferentialDemodulatorVector64(double sampleRate, int symbolRate)
+ public DifferentialDemodulatorFloatVector64(double sampleRate, int symbolRate)
{
super(sampleRate, symbolRate);
}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/pll/AdaptivePLLBandwidthMonitor.java b/src/main/java/io/github/dsheirer/dsp/psk/pll/AdaptivePLLBandwidthMonitor.java
deleted file mode 100644
index 3e2cd1b9..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/pll/AdaptivePLLBandwidthMonitor.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- *
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * This program is distributed in the hope that it will be useful,
- * * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * * GNU General Public License for more details.
- * *
- * * You should have received a copy of the GNU General Public License
- * * along with this program. If not, see
- * * *****************************************************************************
- *
- *
- */
-package io.github.dsheirer.dsp.psk.pll;
-
-import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
-import io.github.dsheirer.module.decode.FeedbackDecoder;
-import io.github.dsheirer.source.SourceEvent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Monitors decode sync events to adaptively control PLL loop gain.
- */
-public class AdaptivePLLBandwidthMonitor implements ISyncDetectListener, IFrequencyErrorProcessor
-{
- private final static Logger mLog = LoggerFactory.getLogger(AdaptivePLLBandwidthMonitor.class);
-
- private static final int MAX_SYNC_COUNT = PLLBandwidth.BW_200.getRangeEnd();
- private CostasLoop mCostasLoop;
- private FeedbackDecoder mFeedbackDecoder;
- private PLLBandwidth mPLLBandwidth = PLLBandwidth.BW_400;
- private int mSyncCount;
-
- /**
- * Constructs an adaptive monitor to monitor the sync state of a decoder and adjust the gain
- * level of the costas loop accordingly.
- *
- * @param costasLoop to receive adaptive gain updates.
- * @param feedbackDecoder to rebroadcast frequency error source events
- */
- public AdaptivePLLBandwidthMonitor(CostasLoop costasLoop, FeedbackDecoder feedbackDecoder)
- {
- mCostasLoop = costasLoop;
- mCostasLoop.setPLLBandwidth(mPLLBandwidth);
- mCostasLoop.setFrequencyErrorProcessor(this);
- mFeedbackDecoder = feedbackDecoder;
- }
-
- /**
- * Sync detection event. Updates the running sync count and updates the PLL gain level.
- */
- @Override
- public void syncDetected(int bitErrors)
- {
- mSyncCount++;
- update();
- }
-
- /**
- * Sync loss event. Updates the running sync count and updates the PLL gain level.
- */
- @Override
- public void syncLost(int bitsProcessed)
- {
- mSyncCount -= 2;
- update();
- }
-
- /**
- * Updates the gain state for a sync detect or sync loss
- */
- private void update()
- {
- if(mSyncCount < 0)
- {
- mSyncCount = 0;
- return;
- }
-
- if(mSyncCount > MAX_SYNC_COUNT)
- {
- mSyncCount = MAX_SYNC_COUNT;
- return;
- }
-
- PLLBandwidth gain = PLLBandwidth.fromSyncCount(mSyncCount);
-
- //Only update the costas loop if the gain value changes
- if(gain != mPLLBandwidth)
- {
- mPLLBandwidth = gain;
- mCostasLoop.setPLLBandwidth(mPLLBandwidth);
- }
- }
-
- /**
- * Resets the monitor and commands the PLL to use the highest gain level.
- */
- public void reset()
- {
- mSyncCount = 0;
- mPLLBandwidth = PLLBandwidth.BW_400;
- mCostasLoop.setPLLBandwidth(mPLLBandwidth);
- }
-
- @Override
- public void processFrequencyError(long frequencyError)
- {
- //Only rebroadcast the costas loop frequency error if the gain level has progressed above
- //a bandwidth of 300, meaning that we have received at least 4 sync events
- if(mPLLBandwidth != PLLBandwidth.BW_400 && mPLLBandwidth != PLLBandwidth.BW_300)
- {
- mFeedbackDecoder.broadcast(SourceEvent.frequencyErrorMeasurement(frequencyError));
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/pll/FrequencyCorrectionSyncMonitor.java b/src/main/java/io/github/dsheirer/dsp/psk/pll/FrequencyCorrectionSyncMonitor.java
index 2cd2358e..b02f04fe 100644
--- a/src/main/java/io/github/dsheirer/dsp/psk/pll/FrequencyCorrectionSyncMonitor.java
+++ b/src/main/java/io/github/dsheirer/dsp/psk/pll/FrequencyCorrectionSyncMonitor.java
@@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory;
/**
* Monitors decode sync events to adaptively control frequency correction broadcasts.
*/
+@Deprecated //Remove after P25P2 decoder gets updated
public class FrequencyCorrectionSyncMonitor implements ISyncDetectListener, IFrequencyErrorProcessor
{
private final static Logger mLog = LoggerFactory.getLogger(FrequencyCorrectionSyncMonitor.class);
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/pll/QPSKPhaseInversionCalculator.java b/src/main/java/io/github/dsheirer/dsp/psk/pll/QPSKPhaseInversionCalculator.java
deleted file mode 100644
index 58ce1688..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/pll/QPSKPhaseInversionCalculator.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- *
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * This program is distributed in the hope that it will be useful,
- * * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * * GNU General Public License for more details.
- * *
- * * You should have received a copy of the GNU General Public License
- * * along with this program. If not, see
- * * *****************************************************************************
- *
- *
- */
-
-package io.github.dsheirer.dsp.psk.pll;
-
-import io.github.dsheirer.dsp.symbol.Dibit;
-
-/**
- * Utility for calculating phase inverted sync pattern derivatives for QPSK constellations
- */
-public class QPSKPhaseInversionCalculator
-{
- public static void main(String[] args)
- {
-
- //DMR sync patterns
-// String[] syncs = {"755FD7DF75F7", "DFF57D75DF5D", "7F7D5DD57DFD", "D5D7F77FD757", "77D55F7DFD77",
-// "5D577F7757FF", "F7FDD5DDFD55", "7DFFD5F55D5F", "D7557F5FF7F5", "DD7FF5D757DD"};
-
- //P25 Phase 2 sync pattern
- String[] syncs = {"575D57F7FF"};
-
- //P25 Phase 1 sync pattern
-// String[] syncs = {"5575F5FF77FF"};
-
-
- for(String sync: syncs)
- {
- StringBuilder sbNorm = new StringBuilder();
- StringBuilder sbP90 = new StringBuilder();
- StringBuilder sbM90 = new StringBuilder();
- StringBuilder sb180 = new StringBuilder();
-
- for(char letter: sync.toCharArray())
- {
- int value;
-
- if(Character.isAlphabetic(letter))
- {
- value = letter - 55;
- }
- else
- {
- value = letter - 48;
- }
-
- sbNorm.append(letter);
- sbP90.append(rotate(value, Dibit.Rotation.PLUS90));
- sbM90.append(rotate(value, Dibit.Rotation.MINUS90));
- sb180.append(rotate(value, Dibit.Rotation.INVERT));
- }
-
- System.out.println("NORMAL: " + sync);
- System.out.println(" +90: " + sbP90);
- System.out.println(" -90: " + sbM90);
- System.out.println(" 180: " + sb180);
- }
- }
-
- /**
- * Converts the hexadecimal value to an integer, decomposes it into high and low order dibits, rotates the dibits
- * in the specified direction, and recombines the rotated dibits into a 4-bit value, returned as a hex character.
- * @param value to rotate
- * @param direction direction
- * @return rotated hex character
- */
- public static String rotate(int value, Dibit.Rotation direction)
- {
- try
- {
- Dibit dibitHigh = getHighDibit(value);
- Dibit dibitLow = getLowDibit(value);
- return getHex(dibitHigh.rotate(direction), dibitLow.rotate(direction));
- }
- catch(Exception e)
- {
- //ignore
- }
-
- return "-";
- }
-
- /**
- * Combines the bit values from the two dibits and converts the integer value to a hex character
- * @param d1 containing the high order bits
- * @param d2 containing the low order bits
- * @return string hex character representing the value of these dibits combined
- */
- public static String getHex(Dibit d1, Dibit d2)
- {
- int value = d1.getHighValue() + d2.getLowValue();
- return Integer.toHexString(value).toUpperCase();
- }
-
- /**
- * Calculates the dibit that represents the bits in the 0x8 and 0x4 bit positions of the value
- * @param value
- * @return a dibit
- */
- public static Dibit getHighDibit(int value)
- {
- return Dibit.fromValue((value >> 2) & 3);
- }
-
- /**
- * Calculates the dibit that represents the bits in the 0x2 and 0x1 bit positions of the value
- * @param value
- * @return a dibit
- */
- public static Dibit getLowDibit(int value)
- {
- return Dibit.fromValue(value & 3);
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/squelch/PowerMonitor.java b/src/main/java/io/github/dsheirer/dsp/squelch/PowerMonitor.java
index ca14acef..0f552dfe 100644
--- a/src/main/java/io/github/dsheirer/dsp/squelch/PowerMonitor.java
+++ b/src/main/java/io/github/dsheirer/dsp/squelch/PowerMonitor.java
@@ -34,14 +34,14 @@ public class PowerMonitor
private int mPowerLevelBroadcastCount = 0;
private int mPowerLevelBroadcastThreshold;
private Listener mSourceEventListener;
- private SinglePoleIirFilter mPowerFilter = new SinglePoleIirFilter(0.1f);
+ private final SinglePoleIirFilter mPowerFilter = new SinglePoleIirFilter(0.1f);
/**
* Constructs an instance
*/
public PowerMonitor()
{
- mPowerLevelBroadcastThreshold = 25000; //Based on a default sample rate of 50 kHz
+ mPowerLevelBroadcastThreshold = 12500; //Based on a default sample rate of 25 kHz
}
/**
@@ -54,36 +54,25 @@ public class PowerMonitor
mPowerLevelBroadcastThreshold = sampleRate / 2;
}
- /**
- * Processes a complex IQ sample and changes squelch state when the signal power is above or below the
- * threshold value.
- * @param inphase complex sample component
- * @param quadrature complex sample component
- */
- public void process(float inphase, float quadrature)
- {
- mPowerLevelBroadcastCount++;
-
- if(mPowerLevelBroadcastCount > mPowerLevelBroadcastThreshold)
- {
- mPowerFilter.filter(inphase * inphase + quadrature * quadrature);
- }
-
- if(mPowerLevelBroadcastCount > (mPowerLevelBroadcastThreshold + 10))
- {
- mPowerLevelBroadcastCount = 0;
- broadcast(SourceEvent.channelPowerLevel(null, 10.0 * Math.log10(mPowerFilter.getValue())));
- }
- }
-
/**
* Processes I&Q complex baseband sample buffers.
*/
public void process(float[] i, float[] q)
{
- for(int x = 0; x < i.length; x++)
+ mPowerLevelBroadcastCount += i.length;
+
+ if(mPowerLevelBroadcastCount > mPowerLevelBroadcastThreshold && i.length >= 10)
{
- process(i[x], q[x]);
+ double iSquared, qSquared;
+ for(int x = 0; x < 10; x++)
+ {
+ iSquared = Math.pow(i[x], 2.0f);
+ qSquared = Math.pow(q[x], 2.0f);
+ mPowerFilter.filter((float)(iSquared + qSquared));
+ }
+
+ mPowerLevelBroadcastCount -= mPowerLevelBroadcastThreshold;
+ broadcast(SourceEvent.channelPowerLevel(null, 10.0 * Math.log10(mPowerFilter.getValue())));
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/symbol/Dibit.java b/src/main/java/io/github/dsheirer/dsp/symbol/Dibit.java
index 6b9230b5..656a9bb4 100644
--- a/src/main/java/io/github/dsheirer/dsp/symbol/Dibit.java
+++ b/src/main/java/io/github/dsheirer/dsp/symbol/Dibit.java
@@ -265,15 +265,24 @@ public enum Dibit
}
}
- public static void main(String[] args)
+ /**
+ * Number of bit errors between this dibit and the expected dibit argument.
+ * @param dibit to compare
+ * @return 0, 1 or 2 bit errors
+ */
+ public int getBitErrorFrom(Dibit dibit)
{
- byte a = (byte)0x1B;
+ int xor = getValue() ^ dibit.getValue();
- Dibit d1 = Dibit.parse(a, 0);
- Dibit d2 = Dibit.parse(a, 1);
- Dibit d3 = Dibit.parse(a, 2);
- Dibit d4 = Dibit.parse(a, 3);
+ if(xor == 0)
+ {
+ return 0;
+ }
+ else if(xor == 3)
+ {
+ return 2;
+ }
- System.out.println("1: " + d1 + " 2:" + d2 + " 3:" + d3 + " 4:" + d4);
+ return 1;
}
}
diff --git a/src/main/java/io/github/dsheirer/dsp/symbol/DibitDelayBuffer.java b/src/main/java/io/github/dsheirer/dsp/symbol/DibitDelayBuffer.java
deleted file mode 100644
index 25131e03..00000000
--- a/src/main/java/io/github/dsheirer/dsp/symbol/DibitDelayBuffer.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- *
- * * ******************************************************************************
- * * Copyright (C) 2014-2019 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * 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.symbol;
-
-import io.github.dsheirer.bits.BitSetFullException;
-import io.github.dsheirer.bits.CorrectedBinaryMessage;
-import org.apache.commons.lang3.Validate;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Circular buffer for storing and accessing dibits.
- */
-public class DibitDelayBuffer
-{
- private final static Logger mLog = LoggerFactory.getLogger(DibitDelayBuffer.class);
-
- protected Dibit[] mBuffer;
- protected int mPointer;
-
- /**
- * Constructs a dibit delay buffer of the specified length
- */
- public DibitDelayBuffer(int length)
- {
- Validate.isTrue(length > 0, "Dibit buffer length must be greater than 0");
- mBuffer = new Dibit[length];
- reset();
- }
-
- /**
- * Resets the buffer and preloads the buffer with all zeros
- */
- public void reset()
- {
- for(int x = 0; x < mBuffer.length; x++)
- {
- mBuffer[x] = Dibit.D00_PLUS_1;
- }
- }
-
- /**
- * Length of this circular buffer
- */
- public int length()
- {
- return mBuffer.length;
- }
-
- /**
- * Returns the dibit at the specified index
- * @param index to get
- * @return dibit at the specified index
- */
- public Dibit get(int index)
- {
- if(index < 0 || index >= mBuffer.length)
- {
- throw new IllegalArgumentException("Index argument must be between 0 and buffer length [" + mBuffer.length + "]");
- }
-
- return mBuffer[index];
- }
-
- /**
- * Sets the dibit at the specified index
- * @param index of the dibit
- * @param dibit to load at the specified index
- */
- public void set(int index, Dibit dibit)
- {
- if(index < 0 || index >= mBuffer.length)
- {
- throw new IllegalArgumentException("Index argument must be between 0 and buffer length [" + mBuffer.length + "]");
- }
-
- mBuffer[index] = dibit;
- }
-
- /**
- * Returns an ordered view of the internal circular buffer contents.
- */
- public Dibit[] getBuffer()
- {
- Dibit[] transferBuffer = new Dibit[mBuffer.length];
-
- int transferBufferPointer = 0;
- int bufferPointer = mPointer;
-
- while(transferBufferPointer < transferBuffer.length)
- {
- transferBuffer[transferBufferPointer++] = mBuffer[bufferPointer++];
-
- if(bufferPointer >= mBuffer.length)
- {
- bufferPointer = 0;
- }
- }
-
- return transferBuffer;
- }
-
- /**
- * Retrieves a view of the buffer from the starting index to the specified length. Note: if the requested
- * length exceeds the length of this buffer, the contents will be unwrapped from the circular buffer and repeated.
- * @param start of the view where 0 is the first element.
- * @param length of the dibit view
- * @return an array of dibits
- */
- public Dibit[] getBuffer(int start, int length)
- {
- Dibit[] transferBuffer = new Dibit[length];
-
- int transferBufferPointer = 0;
- int bufferPointer = (mPointer + start) % mBuffer.length;
-
- while(transferBufferPointer < transferBuffer.length)
- {
- transferBuffer[transferBufferPointer++] = mBuffer[bufferPointer++];
-
- if(bufferPointer >= mBuffer.length)
- {
- bufferPointer = 0;
- }
- }
-
- return transferBuffer;
- }
-
- /**
- * Extracts a corrected binary message from the dibit buffer
- *
- * @param start dibit index where 0 is the oldest dibit and the newest dibit is buffer length - 1
- * @param dibitLength number of dibits to include in the message, making the message length = dibitLength * 2
- * @return corrected binary message
- */
- public CorrectedBinaryMessage getMessage(int start, int dibitLength)
- {
- CorrectedBinaryMessage message = new CorrectedBinaryMessage(dibitLength * 2);
-
- int dibitCount = 0;
- int bufferPointer = (mPointer + start) % mBuffer.length;
-
- try
- {
- while(dibitCount < dibitLength)
- {
- Dibit dibit = mBuffer[bufferPointer++];
- message.add(dibit.getBit1());
- message.add(dibit.getBit2());
- dibitCount++;
-
- if(bufferPointer >= mBuffer.length)
- {
- bufferPointer = 0;
- }
- }
- }
- catch(BitSetFullException e)
- {
- //This shouldn't happen
- mLog.error("Bit set full ??", e);
- }
-
- return message;
- }
-
- /**
- * Utility method to view the buffer contents with the dibits decoded as an array of zeros and ones.
- */
- public int[] getBufferAsArray()
- {
- Dibit[] dibits = getBuffer();
-
- int[] bits = new int[dibits.length * 2];
-
- for(int x = 0; x < dibits.length; x++)
- {
- if(dibits[x].getBit1())
- {
- bits[x * 2] = 1;
- }
- if(dibits[x].getBit2())
- {
- bits[x * 2 + 1] = 1;
- }
- }
-
- return bits;
- }
-
- /**
- * Places the dibit into the internal circular buffer, overwriting the oldest dibit.
- */
- public void put(Dibit dibit)
- {
- mBuffer[mPointer++] = dibit;
-
- if(mPointer >= mBuffer.length)
- {
- mPointer = 0;
- }
- }
-
- /**
- * Places the dibit into the internal circular buffer, overwriting and returning the
- * oldest dibit.
- */
- public Dibit getAndPut(Dibit dibit)
- {
- Dibit toReturn = mBuffer[mPointer];
- put(dibit);
- return toReturn;
- }
-
- /**
- * Logs the contents of the buffer
- */
- public void log()
- {
- StringBuilder sb = new StringBuilder();
-
- int counter = 0;
- int pointer = mPointer;
-
- while(counter < mBuffer.length)
- {
- sb.append(mBuffer[pointer].getBit1() ? "1" : "0");
- sb.append(mBuffer[pointer++].getBit2() ? "1" : "0");
-
- if(pointer >= mBuffer.length)
- {
- pointer = 0;
- }
-
- counter++;
- }
- mLog.debug("BUFFER: " + sb + " Length:" + mBuffer.length);
- }
-}
diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/DibitDelayLine.java b/src/main/java/io/github/dsheirer/dsp/symbol/DibitDelayLine.java
similarity index 74%
rename from src/main/java/io/github/dsheirer/module/decode/dmr/DibitDelayLine.java
rename to src/main/java/io/github/dsheirer/dsp/symbol/DibitDelayLine.java
index d2b25615..9ad6403a 100644
--- a/src/main/java/io/github/dsheirer/module/decode/dmr/DibitDelayLine.java
+++ b/src/main/java/io/github/dsheirer/dsp/symbol/DibitDelayLine.java
@@ -17,9 +17,8 @@
* ****************************************************************************
*/
-package io.github.dsheirer.module.decode.dmr;
+package io.github.dsheirer.dsp.symbol;
-import io.github.dsheirer.dsp.symbol.Dibit;
import java.util.Arrays;
/**
@@ -27,9 +26,8 @@ import java.util.Arrays;
*/
public class DibitDelayLine
{
- private Dibit[] mDelayLine;
+ protected Dibit[] mDelayLine;
public int mPointer;
- private int mLength;
/**
* Constructs an instance
@@ -37,7 +35,6 @@ public class DibitDelayLine
*/
public DibitDelayLine(int length)
{
- mLength = length;
mDelayLine = new Dibit[length];
Arrays.fill(mDelayLine, Dibit.D00_PLUS_1);
}
@@ -51,7 +48,7 @@ public class DibitDelayLine
{
Dibit ejected = mDelayLine[mPointer];
mDelayLine[mPointer++] = dibit;
- mPointer %= mLength;
+ mPointer %= mDelayLine.length;
return ejected;
}
@@ -72,10 +69,44 @@ public class DibitDelayLine
for(Dibit dibit: dibits)
{
mDelayLine[mPointer++] = dibit;
- mPointer %= mLength;
+ mPointer %= mDelayLine.length;
}
}
+ /**
+ * Adjusts the pointer to correct a dibit stuff/delete.
+ * @param offset to adjust.
+ */
+ public void adjustPointer(int offset)
+ {
+ mPointer += offset;
+
+ if(mPointer < 0)
+ {
+ mPointer += mDelayLine.length;
+ }
+ else if(mPointer >= mDelayLine.length)
+ {
+ mPointer -= mDelayLine.length;
+ }
+ }
+
+
+ /**
+ * Returns the most recently stored Dibit.
+ */
+ public Dibit getLast()
+ {
+ int pointer = mPointer - 1;
+
+ if(pointer < 0)
+ {
+ pointer += mDelayLine.length;
+ }
+
+ return mDelayLine[pointer];
+ }
+
public void log()
{
StringBuilder sb = new StringBuilder();
@@ -89,7 +120,7 @@ public class DibitDelayLine
sb.append(" ");
pointer++;
- pointer = pointer % mLength;
+ pointer = pointer % mDelayLine.length;
}
System.out.println(sb);
diff --git a/src/main/java/io/github/dsheirer/edac/BCH_63_16_11.java b/src/main/java/io/github/dsheirer/edac/BCH_63_16_11.java
deleted file mode 100644
index aac7e24a..00000000
--- a/src/main/java/io/github/dsheirer/edac/BCH_63_16_11.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2020 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see
- * ****************************************************************************
- */
-
-package io.github.dsheirer.edac;
-
-import io.github.dsheirer.bits.BinaryMessage;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class BCH_63_16_11 extends ReedSolomon_63_P25
-{
- private final static Logger mLog = LoggerFactory.getLogger(BCH_63_16_11.class);
-
- /**
- * BCH( 63,16,11) decoder
- */
- public BCH_63_16_11()
- {
- super(63, 41);
- }
-
- /**
- * Performs error detection and correction on the first 63 bits of the
- * message argument. If the message is correctable, only the first 16 bits
- * (information bits) are corrected.
- *
- * @return - true = success, false = failure
- */
- public BinaryMessage correctNID(BinaryMessage message)
- {
- CRC status = CRC.PASSED;
-
- int[] original = message.toReverseIntegerArray(0, 62);
- int[] corrected = new int[63];
-
- boolean irrecoverableErrors = decode(original, corrected);
-
- if(irrecoverableErrors)
- {
- message.setCRC(CRC.FAILED_CRC);
-
- return message;
- }
- else
- {
- for(int x = 0; x < 16; x++)
- {
- int index = 63 - x - 1;
-
- if(corrected[index] != original[index])
- {
- status = CRC.CORRECTED;
-
- if(corrected[index] == 1)
- {
- message.set(x);
- }
- else
- {
- message.clear(x);
- }
- }
- }
- }
-
- message.setCRC(status);
-
- return message;
- }
-
- public static void main(String[] args)
- {
- String orig = "0010011000000011010010100000000110000111110011101010001010110000";
- String error = "0001010100000011010010100000000110000111100011001010001010110000";
-
- BinaryMessage errorMessage = BinaryMessage.load(error);
-
- BCH_63_16_11 bch = new BCH_63_16_11();
-
- mLog.debug("ORIG:" + orig);
- mLog.debug(" ERR:" + errorMessage.toString());
- mLog.debug(" ");
-
- errorMessage = bch.correctNID(errorMessage);
-
- mLog.debug(" CRC: " + errorMessage.getCRC().name());
- mLog.debug("CORR:" + errorMessage.toString());
- mLog.debug("ORIG:" + orig);
- }
-}
diff --git a/src/main/java/io/github/dsheirer/edac/ReedSolomon_63_P25.java b/src/main/java/io/github/dsheirer/edac/ReedSolomon_63_P25.java
index 38f61142..9edc5c94 100644
--- a/src/main/java/io/github/dsheirer/edac/ReedSolomon_63_P25.java
+++ b/src/main/java/io/github/dsheirer/edac/ReedSolomon_63_P25.java
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
- * Copyright (C) 2014-2020 Dennis Sheirer
+ * Copyright (C) 2014-2025 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
@@ -27,7 +27,7 @@ public class ReedSolomon_63_P25 extends BerlekempMassey
/**
* APCO-25 Reed-Solomon code is generated from a Galois Field(2^6) by the polynomial: a6 + a1 + a0.
* In binary, this is expressed as: 1000011 which is reversed to big-endian format for this algorithm
- * See: TIA 102-BAAA paragraph 5.9 Reed-Solomon Code Generator Matrices
+ * See: TIA 102-BAAA paragraph 4.9 Reed-Solomon Code Generator Matrices
*/
public static final int[] P25_GENERATOR_POLYNOMIAL = { 1, 1, 0, 0, 0, 0, 1 };
diff --git a/src/main/java/io/github/dsheirer/edac/bch/BCH.java b/src/main/java/io/github/dsheirer/edac/bch/BCH.java
index d2d17d3c..969d8aa9 100644
--- a/src/main/java/io/github/dsheirer/edac/bch/BCH.java
+++ b/src/main/java/io/github/dsheirer/edac/bch/BCH.java
@@ -324,6 +324,13 @@ public abstract class BCH
/* add a^(k*2^i)(z^(2^i) mod f) and compute (z^(2^i) mod f)^2 */
for (j = z.mDegree; j >= 0; j--)
{
+ if(2 * j >= z.mC.length)
+ {
+ //Fail ... set degree to 0 to signal fail
+ outTK.mDegree = 0;
+ return outTK;
+ }
+
outTK.mC[j] ^= z.mC[j];
z.mC[2 * j] = gf_sqr(z.mC[j]);
z.mC[2 * j + 1] = 0;
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/RecentFilesMenu.java b/src/main/java/io/github/dsheirer/gui/RecentFilesMenu.java
similarity index 89%
rename from src/main/java/io/github/dsheirer/gui/instrument/RecentFilesMenu.java
rename to src/main/java/io/github/dsheirer/gui/RecentFilesMenu.java
index 5b8f1d20..02193fd9 100644
--- a/src/main/java/io/github/dsheirer/gui/instrument/RecentFilesMenu.java
+++ b/src/main/java/io/github/dsheirer/gui/RecentFilesMenu.java
@@ -1,29 +1,31 @@
-/*******************************************************************************
- * sdr-trunk
- * Copyright (C) 2014-2018 Dennis Sheirer
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2025 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
- *
- ******************************************************************************/
-package io.github.dsheirer.gui.instrument;
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
+package io.github.dsheirer.gui;
+import java.io.File;
+import java.util.prefs.Preferences;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
-import java.io.File;
-import java.util.prefs.Preferences;
-
public class RecentFilesMenu extends Menu implements EventHandler
{
private static final String PREFERENCE_RECENT_FILE = ".recent.file.";
diff --git a/src/main/java/io/github/dsheirer/gui/channel/ChannelSpectrumPanel.java b/src/main/java/io/github/dsheirer/gui/channel/ChannelSpectrumPanel.java
index b8a23e49..0e8d1e4a 100644
--- a/src/main/java/io/github/dsheirer/gui/channel/ChannelSpectrumPanel.java
+++ b/src/main/java/io/github/dsheirer/gui/channel/ChannelSpectrumPanel.java
@@ -23,7 +23,9 @@ import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.dsp.filter.channelizer.PolyphaseChannelSource;
import io.github.dsheirer.gui.power.SignalPowerView;
import io.github.dsheirer.gui.squelch.NoiseSquelchView;
+import io.github.dsheirer.gui.symbol.SymbolView;
import io.github.dsheirer.module.ProcessingChain;
+import io.github.dsheirer.module.decode.FeedbackDecoder;
import io.github.dsheirer.module.decode.PrimaryDecoder;
import io.github.dsheirer.module.decode.am.AMDecoder;
import io.github.dsheirer.module.decode.nbfm.NBFMDecoder;
@@ -46,13 +48,14 @@ import java.awt.EventQueue;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
+import java.net.URL;
import java.text.DecimalFormat;
-import java.text.NumberFormat;
import java.util.List;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import net.miginfocom.swing.MigLayout;
+import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -70,7 +73,7 @@ import javax.swing.event.MouseInputAdapter;
*/
public class ChannelSpectrumPanel extends JPanel implements Listener
{
- private static final Logger mLog = LoggerFactory.getLogger(ChannelSpectrumPanel.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(ChannelSpectrumPanel.class);
private static final DecimalFormat FREQUENCY_FORMAT = new DecimalFormat("0.00000");
private final PlaylistManager mPlaylistManager;
private ProcessingChain mProcessingChain;
@@ -80,13 +83,14 @@ public class ChannelSpectrumPanel extends JPanel implements Listener {
@@ -144,8 +145,8 @@ public class ChannelSpectrumPanel extends JPanel implements Listener hbtcs)
{
@@ -153,11 +154,11 @@ public class ChannelSpectrumPanel extends JPanel implements Listener {
Scene scene = new Scene(mNoiseSquelchView);
mNoiseSquelchPanel.setScene(scene);
+ Scene scene2 = new Scene(mSymbolView);
+ URL resource = getClass().getResource("/sdrtrunk_style.css");
+
+ if(resource != null)
+ {
+ scene2.getStylesheets().add(resource.toExternalForm());
+ }
+ else
+ {
+ LOGGER.warn("Can't find stylesheet resource for sdrtrunk");
+ }
+
+ mSymbolPanel.setScene(scene2);
});
mSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
mSplitPane.add(fftPanel, JSplitPane.LEFT);
mSplitPane.add(mNoiseSquelchPanel, JSplitPane.RIGHT);
- mSplitPane.setDividerLocation(0.5);
add(mSplitPane);
+// mSplitPane.setDividerLocation(0.5);
mSampleStreamTapModule.setListener(mComplexDftProcessor);
DFTResultsConverter DFTResultsConverter = new ComplexDecibelConverter();
@@ -214,6 +229,13 @@ public class ChannelSpectrumPanel extends JPanel implements Listener {
- String formattedValue = NumberFormat.getInstance().format(carrierOffsetFrequency);
- mEstimatedCarrierOffsetFrequencyValueLabel.setText(formattedValue + " Hz");
+ mEstimatedCarrierOffsetFrequencyValueLabel.setText(getPaddedCarrierOffsetLabel(carrierOffsetFrequency));
mEstimatedCarrierOffsetFrequencyValueLabel.setEnabled(true);
- mEstimatedCarrierOffsetFrequencyLabel.setEnabled(true);
});
mFrequencyOverlayPanel.setEstimatedCarrierOffsetFrequency(carrierOffsetFrequency);
@@ -306,8 +327,7 @@ public class ChannelSpectrumPanel extends JPanel implements Listener
- * * *****************************************************************************
- *
- *
- */
-package io.github.dsheirer.gui.instrument;
-
-import io.github.dsheirer.gui.instrument.decoder.DecoderPaneFactory;
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.p25.phase1.P25P1Decoder;
-import javafx.application.Application;
-import javafx.application.Platform;
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
-import javafx.scene.Scene;
-import javafx.scene.control.Menu;
-import javafx.scene.control.MenuBar;
-import javafx.scene.control.MenuItem;
-import javafx.scene.control.SeparatorMenuItem;
-import javafx.scene.layout.BorderPane;
-import javafx.stage.FileChooser;
-import javafx.stage.Stage;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.util.prefs.Preferences;
-
-/**
- * Application for viewing and working with demodulators and recording files.
- */
-public class DemodulatorViewerFX extends Application
-{
- private final static Logger mLog = LoggerFactory.getLogger(DemodulatorViewerFX.class);
-
- private static final String PREFERENCE_FILE_OPEN_DEFAULT_FOLDER = "default.folder";
-
- private Preferences mPreferences = Preferences.userNodeForPackage(DemodulatorViewerFX.class);
- private Stage mStage;
- private MenuBar mMenuBar;
- private RecentFilesMenu mRecentFilesMenu;
- private ViewerDesktop mViewerDesktop;
-
- @Override
- public void start(Stage primaryStage) throws Exception
- {
- mStage = primaryStage;
- setTitle();
-
- BorderPane borderPane = new BorderPane();
- borderPane.setTop(getMenuBar());
- borderPane.setCenter(getViewerDesktop());
-
- Scene scene = new Scene(borderPane, 1800, 900);
-
- mStage.setScene(scene);
- mStage.show();
- }
-
- private void setTitle()
- {
- mStage.setTitle("Demodulator Viewer FX");
- }
-
- private void setTitle(DecoderType decoderType)
- {
- if(decoderType != null)
- {
- mStage.setTitle("Demodulator Viewer FX - " + decoderType.getDisplayString());
- }
- else
- {
- setTitle();
- }
- }
-
- private void setTitle(P25P1Decoder.Modulation modulation)
- {
- if(modulation != null)
- {
- mStage.setTitle("Demodulator Viewer FX - P25 " + modulation.getLabel());
- }
- else
- {
- setTitle();
- }
- }
-
- private ViewerDesktop getViewerDesktop()
- {
- if(mViewerDesktop == null)
- {
- mViewerDesktop = new ViewerDesktop();
- }
-
- return mViewerDesktop;
- }
-
- private MenuBar getMenuBar()
- {
- if(mMenuBar == null)
- {
- mMenuBar = new MenuBar();
-
- Menu fileMenu = new Menu("File");
- MenuItem openMenuItem = new MenuItem("Open ...");
- openMenuItem.setOnAction(new EventHandler()
- {
- @Override
- public void handle(ActionEvent event)
- {
- FileChooser fileChooser = new FileChooser();
- fileChooser.setTitle("Open an I/Q recording file");
-
- String directory = mPreferences.get(PREFERENCE_FILE_OPEN_DEFAULT_FOLDER, null);
-
- if(directory != null)
- {
- fileChooser.setInitialDirectory(new File(directory));
- }
-
- File file = fileChooser.showOpenDialog(mStage);
-
- if(file != null)
- {
- getViewerDesktop().load(file);
- getRecentFilesMenu().add(file);
- mPreferences.put(PREFERENCE_FILE_OPEN_DEFAULT_FOLDER, file.getParent());
- }
- }
- });
-
- MenuItem closeMenuItem = new MenuItem("Close");
- closeMenuItem.setOnAction(new EventHandler()
- {
- @Override
- public void handle(ActionEvent event)
- {
- getViewerDesktop().close();
- }
- });
-
- MenuItem exitMenuItem = new MenuItem("Exit");
- exitMenuItem.setOnAction(new EventHandler()
- {
- @Override
- public void handle(ActionEvent event)
- {
- Platform.exit();
- }
- });
-
- fileMenu.getItems().addAll(openMenuItem, getRecentFilesMenu(), closeMenuItem, new SeparatorMenuItem(),
- exitMenuItem);
-
- mMenuBar.getMenus().add(fileMenu);
-
- Menu decoderMenu = new Menu("Decoder");
-
- for(DecoderType decoderType: DecoderType.values())
- {
- if(DecoderPaneFactory.isSupported(decoderType))
- {
- if(decoderType == DecoderType.P25_PHASE1)
- {
- MenuItem c4fmDecoderMenuItem = new MenuItem("P25 Phase 1 C4FM");
-
- c4fmDecoderMenuItem.setOnAction(new EventHandler()
- {
- @Override
- public void handle(ActionEvent event)
- {
- getViewerDesktop().setP25Phase1Decoder(P25P1Decoder.Modulation.C4FM);
- setTitle(decoderType);
- }
- });
-
- decoderMenu.getItems().add(c4fmDecoderMenuItem);
-
- MenuItem lsmDecoderMenuItem = new MenuItem("P25 Phase 1 LSM");
-
- lsmDecoderMenuItem.setOnAction(new EventHandler()
- {
- @Override
- public void handle(ActionEvent event)
- {
- getViewerDesktop().setP25Phase1Decoder(P25P1Decoder.Modulation.CQPSK);
- setTitle(decoderType);
- }
- });
-
- decoderMenu.getItems().add(lsmDecoderMenuItem);
- }
- else
- {
- MenuItem decoderMenuItem = new MenuItem(decoderType.getDisplayString());
-
- decoderMenuItem.setOnAction(new EventHandler()
- {
- @Override
- public void handle(ActionEvent event)
- {
- getViewerDesktop().setDecoder(decoderType);
- setTitle(decoderType);
- }
- });
-
- decoderMenu.getItems().add(decoderMenuItem);
- }
- }
- }
-
- mMenuBar.getMenus().add(decoderMenu);
- }
-
- return mMenuBar;
- }
-
- private RecentFilesMenu getRecentFilesMenu()
- {
- if(mRecentFilesMenu == null)
- {
- mRecentFilesMenu = new RecentFilesMenu("Recent","demodulator.viewer", 5);
- mRecentFilesMenu.setFileSelectionListener(new RecentFilesMenu.IFileSelectionListener()
- {
- @Override
- public void fileSelected(File file)
- {
- getViewerDesktop().load(file);
- }
- });
- }
-
- return mRecentFilesMenu;
- }
-
- public static void main(String[] args)
- {
- launch(args);
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/PlaybackController.java b/src/main/java/io/github/dsheirer/gui/instrument/PlaybackController.java
deleted file mode 100644
index 2987b195..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/PlaybackController.java
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.gui.instrument;
-
-import io.github.dsheirer.buffer.INativeBuffer;
-import io.github.dsheirer.gui.instrument.decoder.AbstractDecoderPane;
-import io.github.dsheirer.sample.Broadcaster;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.source.IControllableFileSource;
-import io.github.dsheirer.source.IFrameLocationListener;
-import io.github.dsheirer.source.wave.ComplexWaveSource;
-import io.github.dsheirer.source.wave.RealWaveSource;
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
-import javafx.geometry.Pos;
-import javafx.scene.control.Alert;
-import javafx.scene.control.Button;
-import javafx.scene.control.ButtonType;
-import javafx.scene.control.Label;
-import javafx.scene.control.TextField;
-import javafx.scene.layout.HBox;
-import jiconfont.icons.font_awesome.FontAwesome;
-import jiconfont.javafx.IconNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.sound.sampled.UnsupportedAudioFileException;
-import java.io.File;
-import java.io.IOException;
-
-public class PlaybackController extends HBox implements IFrameLocationListener
-{
- private final static Logger mLog = LoggerFactory.getLogger(PlaybackController.class);
-
- private Button mRewindButton;
- private TextField mPlaybackPositionText;
- private Button mPlay1Button;
- private Button mPlay10Button;
- private Button mPlay30Button;
- private Button mPlay100Button;
- private Button mPlay1000Button;
- private Button mPlay2000Button;
- private HBox mControlsBox;
- private Label mFileLabel;
- private EventHandler mPlayEventHandler;
- private AbstractDecoderPane mSampleRateListener;
-
- private IControllableFileSource mControllableFileSource;
- private Broadcaster mRealBufferBroadcaster = new Broadcaster<>();
- private Broadcaster mNativeBufferBroadcaster = new Broadcaster<>();
-
- public PlaybackController()
- {
- super(10);
-
- getChildren().addAll(getControlsBox(), getFileLabel());
-
- disableControls();
- }
-
- public void setSampleRateListener(AbstractDecoderPane decoderPane)
- {
- mSampleRateListener = decoderPane;
-
- if(mSampleRateListener != null && mControllableFileSource != null)
- {
- mSampleRateListener.setSampleRate(mControllableFileSource.getSampleRate());
- }
- }
-
- public void load(File file)
- {
- if(file != null && file.isFile())
- {
- if(ComplexWaveSource.supports(file))
- {
- try
- {
- mControllableFileSource = new ComplexWaveSource(file);
- mControllableFileSource.setListener(this);
- ((ComplexWaveSource)mControllableFileSource).setListener(mNativeBufferBroadcaster);
- mControllableFileSource.open();
-
- if(mSampleRateListener != null)
- {
- mSampleRateListener.setSampleRate(mControllableFileSource.getSampleRate());
- }
- }
- catch(UnsupportedAudioFileException e)
- {
- mLog.error("Unsupported Audio File Type [" + (file != null ? file.getAbsolutePath() : "null") + "]");
-
- Alert alert = new Alert(Alert.AlertType.ERROR, "The file type is unsupported.", ButtonType.OK);
- alert.show();
- return;
- }
- catch(IOException ioe)
- {
- mLog.error("Error opening file [" + (file != null ? file.getAbsolutePath() : "null") + "]", ioe);
-
- Alert alert = new Alert(Alert.AlertType.ERROR, "There was an error opening the file",
- ButtonType.OK);
- alert.show();
- return;
- }
-
- enableControls();
- }
- else if(RealWaveSource.supports(file))
- {
- try
- {
- mControllableFileSource = new RealWaveSource(file);
- mControllableFileSource.setListener(this);
- ((RealWaveSource)mControllableFileSource).setListener(mRealBufferBroadcaster);
- mControllableFileSource.open();
-
- if(mSampleRateListener != null)
- {
- mSampleRateListener.setSampleRate(mControllableFileSource.getSampleRate());
- }
- }
- catch(UnsupportedAudioFileException e)
- {
- mLog.error("Unsupported Audio File Type [" + (file != null ? file.getAbsolutePath() : "null") + "]");
-
- Alert alert = new Alert(Alert.AlertType.ERROR, "The file type is unsupported.", ButtonType.OK);
- alert.show();
- return;
- }
- catch(IOException ioe)
- {
- mLog.error("Error opening file [" + (file != null ? file.getAbsolutePath() : "null") + "]", ioe);
-
- Alert alert = new Alert(Alert.AlertType.ERROR, "There was an error opening the file",
- ButtonType.OK);
- alert.show();
- return;
- }
-
- enableControls();
- }
-
- getFileLabel().setText(file.getName());
- }
- }
-
- public void close()
- {
- if(mControllableFileSource != null)
- {
- try
- {
- mControllableFileSource.close();
- }
- catch(IOException ioe)
- {
- mLog.error("Error closing file", ioe);
- }
- }
-
- disableControls();
- }
-
- /**
- * Adds listener to receive real buffers from this playback
- */
- public void addRealListener(Listener listener)
- {
- mRealBufferBroadcaster.addListener(listener);
- }
-
- /**
- * Removes the listener from receiving real buffers from this playback
- */
- public void removeRealListener(Listener listener)
- {
- mRealBufferBroadcaster.removeListener(listener);
- }
-
- /**
- * Adds listener to receive complex buffers from this playback
- */
- public void addComplexListener(Listener listener)
- {
- mNativeBufferBroadcaster.addListener(listener);
- }
-
- /**
- * Removes the listener from receiving compex buffers from this playback
- */
- public void removeComplexListener(Listener listener)
- {
- mNativeBufferBroadcaster.removeListener(listener);
- }
-
- /**
- * Sets all of the playback controls to the specified enabled state.
- */
- private void disableControls()
- {
- getRewindButton().setDisable(true);
- getPlaybackPositionText().setDisable(true);
- getPlay1Button().setDisable(true);
- getPlay10Button().setDisable(true);
- getPlay30Button().setDisable(true);
- getPlay100Button().setDisable(true);
- getPlay1000Button().setDisable(true);
- getPlay2000Button().setDisable(true);
- }
-
- /**
- * Sets all of the playback controls to the specified enabled state.
- */
- private void enableControls()
- {
- getRewindButton().setDisable(false);
- getPlaybackPositionText().setDisable(false);
- getPlay1Button().setDisable(false);
- getPlay10Button().setDisable(false);
- getPlay30Button().setDisable(false);
- getPlay100Button().setDisable(false);
- getPlay1000Button().setDisable(false);
- getPlay2000Button().setDisable(false);
- }
-
- private HBox getControlsBox()
- {
- if(mControlsBox == null)
- {
- mControlsBox = new HBox();
-
- mControlsBox.getChildren().addAll(getRewindButton(), getPlaybackPositionText(), getPlay1Button(),
- getPlay10Button(), getPlay30Button(), getPlay100Button(), getPlay1000Button(), getPlay2000Button());
- }
-
- return mControlsBox;
- }
-
-
- private Button getRewindButton()
- {
- if(mRewindButton == null)
- {
- mRewindButton = new Button();
- IconNode iconNode = new IconNode(FontAwesome.FAST_BACKWARD);
- iconNode.setIconSize(10);
- mRewindButton.setGraphic(iconNode);
- }
-
- return mRewindButton;
- }
-
- private Button getPlay1Button()
- {
- if(mPlay1Button == null)
- {
- mPlay1Button = new Button("1");
- mPlay1Button.setUserData(1);
- mPlay1Button.setOnAction(getPlaybackEventHandler());
- IconNode iconNode = new IconNode(FontAwesome.PLAY);
- iconNode.setIconSize(10);
- mPlay1Button.setGraphic(iconNode);
- }
-
- return mPlay1Button;
- }
-
- private Button getPlay10Button()
- {
- if(mPlay10Button == null)
- {
- mPlay10Button = new Button("10");
- mPlay10Button.setUserData(10);
- mPlay10Button.setOnAction(getPlaybackEventHandler());
- IconNode iconNode = new IconNode(FontAwesome.FAST_FORWARD);
- iconNode.setIconSize(10);
- mPlay10Button.setGraphic(iconNode);
- }
-
- return mPlay10Button;
- }
-
- private Button getPlay30Button()
- {
- if(mPlay30Button == null)
- {
- mPlay30Button = new Button("30");
- mPlay30Button.setUserData(30);
- mPlay30Button.setOnAction(getPlaybackEventHandler());
- IconNode iconNode = new IconNode(FontAwesome.FAST_FORWARD);
- iconNode.setIconSize(10);
- mPlay30Button.setGraphic(iconNode);
- }
-
- return mPlay30Button;
- }
-
- private Button getPlay100Button()
- {
- if(mPlay100Button == null)
- {
- mPlay100Button = new Button("100");
- mPlay100Button.setUserData(100);
- mPlay100Button.setOnAction(getPlaybackEventHandler());
- IconNode iconNode = new IconNode(FontAwesome.FAST_FORWARD);
- iconNode.setIconSize(10);
- mPlay100Button.setGraphic(iconNode);
- }
-
- return mPlay100Button;
- }
-
- private Button getPlay1000Button()
- {
- if(mPlay1000Button == null)
- {
- mPlay1000Button = new Button("1000");
- mPlay1000Button.setUserData(1000);
- mPlay1000Button.setOnAction(getPlaybackEventHandler());
- IconNode iconNode = new IconNode(FontAwesome.FAST_FORWARD);
- iconNode.setIconSize(10);
- mPlay1000Button.setGraphic(iconNode);
- }
-
- return mPlay1000Button;
- }
-
- private Button getPlay2000Button()
- {
- if(mPlay2000Button == null)
- {
- mPlay2000Button = new Button("2000");
- mPlay2000Button.setUserData(2000);
- mPlay2000Button.setOnAction(getPlaybackEventHandler());
- IconNode iconNode = new IconNode(FontAwesome.FAST_FORWARD);
- iconNode.setIconSize(10);
- mPlay2000Button.setGraphic(iconNode);
- }
-
- return mPlay2000Button;
- }
-
- private EventHandler getPlaybackEventHandler()
- {
- if(mPlayEventHandler == null)
- {
- mPlayEventHandler = new EventHandler()
- {
- @Override
- public void handle(ActionEvent event)
- {
- int count = (int)((Button)event.getSource()).getUserData();
-
- if(mControllableFileSource != null)
- {
- try
- {
- mControllableFileSource.next(count, true);
- }
- catch(IOException ioe)
- {
- mLog.error("Error while playing samples");
- }
- }
-
- }
- };
- }
-
- return mPlayEventHandler;
- }
-
- private TextField getPlaybackPositionText()
- {
- if(mPlaybackPositionText == null)
- {
- mPlaybackPositionText = new TextField("0");
- mPlaybackPositionText.setAlignment(Pos.CENTER);
- mPlaybackPositionText.setPrefWidth(80);
- }
-
- return mPlaybackPositionText;
- }
-
- private Label getFileLabel()
- {
- if(mFileLabel == null)
- {
- mFileLabel = new Label();
- }
-
- return mFileLabel;
- }
-
- @Override
- public void frameLocationUpdated(int location)
- {
- getPlaybackPositionText().setText(String.valueOf(location));
- }
-
- @Override
- public void frameLocationReset()
- {
- mLog.info("Frame location reset ... ignoring?");
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/ViewerDesktop.java b/src/main/java/io/github/dsheirer/gui/instrument/ViewerDesktop.java
deleted file mode 100644
index d94b2183..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/ViewerDesktop.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.gui.instrument;
-
-import io.github.dsheirer.gui.instrument.decoder.AbstractDecoderPane;
-import io.github.dsheirer.gui.instrument.decoder.DecoderPaneFactory;
-import io.github.dsheirer.gui.instrument.decoder.RealDecoderPane;
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.p25.phase1.P25P1Decoder;
-import javafx.scene.layout.BorderPane;
-
-import java.io.File;
-
-public class ViewerDesktop extends BorderPane
-{
- private PlaybackController mPlaybackController;
- private AbstractDecoderPane mDecoderPane = DecoderPaneFactory.getDefaultPane();
-
- public ViewerDesktop()
- {
- setBottom(getPlaybackController());
- setCenter(getDecoderPane());
- }
-
- public void load(File file)
- {
- close();
- getPlaybackController().load(file);
- }
-
- public void setDecoder(DecoderType decoderType)
- {
- setDecoderPane(DecoderPaneFactory.getDecoderPane(decoderType));
- }
-
- public void setP25Phase1Decoder(P25P1Decoder.Modulation modulation)
- {
- setDecoderPane(DecoderPaneFactory.getP25P1DecoderPane(modulation));
- }
-
- private void setDecoderPane(AbstractDecoderPane decoderPane)
- {
- if(getDecoderPane() instanceof RealDecoderPane)
- {
- getPlaybackController().removeRealListener(getDecoderPane());
- }
- else
- {
- getPlaybackController().removeComplexListener(getDecoderPane());
- }
- getChildren().remove(getDecoderPane());
- mDecoderPane = decoderPane;
- setCenter(getDecoderPane());
-
- if(getDecoderPane() instanceof RealDecoderPane)
- {
- getPlaybackController().addRealListener(getDecoderPane());
- }
- else
- {
- getPlaybackController().addComplexListener(getDecoderPane());
- }
- getPlaybackController().setSampleRateListener(getDecoderPane());
- }
-
- /**
- * Decoder pane
- */
- public AbstractDecoderPane getDecoderPane()
- {
- if(mDecoderPane == null)
- {
- mDecoderPane = DecoderPaneFactory.getDefaultPane();
- }
-
- return mDecoderPane;
- }
-
- public void close()
- {
- getPlaybackController().close();
- }
-
- private PlaybackController getPlaybackController()
- {
- if(mPlaybackController == null)
- {
- mPlaybackController = new PlaybackController();
- }
-
- return mPlaybackController;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/AFSK1200SampleBufferChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/AFSK1200SampleBufferChart.java
deleted file mode 100644
index 9c861dc0..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/AFSK1200SampleBufferChart.java
+++ /dev/null
@@ -1,169 +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.gui.instrument.chart;
-
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.chart.LineChart;
-import javafx.scene.chart.NumberAxis;
-import javafx.scene.layout.StackPane;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class AFSK1200SampleBufferChart extends LineChart
-{
- private final static Logger mLog = LoggerFactory.getLogger(AFSK1200SampleBufferChart.class);
- private ObservableList> mSamples = FXCollections.observableArrayList();
- private Series mSampleSeries = new Series<>("Samples", mSamples);
-
- private ObservableList> mSamplePoints = FXCollections.observableArrayList();
- private Series mSamplePointSeries = new Series<>("Pointers", mSamplePoints);
-
- private ObservableList> mSymbolSamples = FXCollections.observableArrayList();
- private Series mSymbolSamplesSeries = new Series<>("Next Symbol Samples", mSymbolSamples);
-
- private ObservableList> mPreviousSymbol = FXCollections.observableArrayList();
- private Series mPreviousSymbolSeries = new Series<>("Previous Symbol", mPreviousSymbol);
-
- private ObservableList> mZeroCrossing = FXCollections.observableArrayList();
- private Series mZeroCrossingSeries = new Series<>("Zero Crossing", mZeroCrossing);
-
- private IInstrumentedAFSK1200Decoder mIInstrumentedAFSK1200Decoder;
-
- public AFSK1200SampleBufferChart(IInstrumentedAFSK1200Decoder decoder, int length)
- {
- super(new NumberAxis("Samples", 0, length, 5),
- new NumberAxis("Value", -1.0, 1.0, 0.25));
-
- ObservableList observableList = FXCollections.observableArrayList(mSampleSeries, mSamplePointSeries,
- mSymbolSamplesSeries, mPreviousSymbolSeries, mZeroCrossingSeries);
-
- setData(observableList);
-
- mIInstrumentedAFSK1200Decoder = decoder;
- decoder.getBufferCountProperty().addListener(new BufferChangeListener());
- decoder.getAFSK1200Decoder().getErrorDetector().timingError.addListener(new ErrorChangeListener());
- }
-
- public void setBuffer(boolean[] buffer)
- {
- while(mSamples.size() < buffer.length)
- {
- Data sample = new Data<>(mSamples.size(), 0.0f);
- mSamples.add(sample);
-
- //Turn off the data point marker symbols - yes I know this is inefficient
- for(Data data: mSampleSeries.getData())
- {
- StackPane stackPane = (StackPane)data.getNode();
- stackPane.setVisible(false);
- }
- }
-
- for(int x = 0; x < buffer.length; x++)
- {
- Data sample = mSamples.get(x);
-
- sample.setYValue(buffer[x] ? 0.5f : -0.5f);
- }
- }
-
- public class BufferChangeListener implements ChangeListener
- {
- @Override
- public void changed(ObservableValue observable, Object oldValue, Object newValue)
- {
- setBuffer(mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getSampleBuffer().getDelayLine());
-
- while(mPreviousSymbol.size() < 2)
- {
- Data sample = new Data<>(0.0, -0.55);
- mPreviousSymbol.add(sample);
- }
-
- while(mZeroCrossing.size() < 2)
- {
- Data sample = new Data<>(0.0, -0.65);
- mZeroCrossing.add(sample);
- }
-
- while(mSamplePoints.size() < 2)
- {
- Data sample = new Data<>(0.0, -0.75);
- mSamplePoints.add(sample);
- }
-
- while(mSymbolSamples.size() < 2)
- {
- Data sample = new Data<>(0.0, -0.85);
- mSymbolSamples.add(sample);
- }
-
- int pointer1 = mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getSampleBuffer().getDelayLinePointer();
- int pointer2 = mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getSampleBuffer().getDelayLineSecondPointer();
-
- mSamplePoints.get(0).setXValue(pointer1);
- mSamplePoints.get(1).setXValue(pointer2);
-
- float samplesPerSymbol = mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getSampleBuffer().getSamplesPerSymbol();
-
- boolean symbol = mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getSampleBuffer().getLastSymbol();
- int symbolStart = mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getSampleBuffer().getSymbolStart();
- int symbolEnd = mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getSampleBuffer().getSymbolEnd();
-
- float start = pointer1 + samplesPerSymbol - 1;
- float end = symbolEnd;
-
- mSymbolSamples.get(0).setXValue(start);
- mSymbolSamples.get(1).setXValue(end);
-
-
- mPreviousSymbol.get(0).setXValue(symbolStart);
- mPreviousSymbol.get(0).setYValue(symbol ? 0.55f : -0.55f);
- mPreviousSymbol.get(1).setXValue(symbolEnd);
- mPreviousSymbol.get(1).setYValue(symbol ? 0.55f : -0.55f);
- }
- }
-
- public class ErrorChangeListener implements ChangeListener
- {
- @Override
- public void changed(ObservableValue observable, Object oldValue, Object newValue)
- {
- while(mZeroCrossing.size() < 2)
- {
- Data sample = new Data<>(0.0, -0.65);
- mZeroCrossing.add(sample);
- }
-
- int pointer1 = mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getSampleBuffer().getDelayLinePointer();
- int pointer2 = mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getSampleBuffer().getDelayLineSecondPointer();
-
- int detectedZeroCrossing = ((Number)newValue).intValue();
-
-// int reference = (zeroCrossingIdeal < pointer1 || detectedZeroCrossing < pointer1 ? pointer2 : pointer1);
-// reference--;
-//
-// float start = reference - zeroCrossingIdeal;
-// float end = reference - detectedZeroCrossing;
-//
-// mZeroCrossing.get(0).setXValue(start);
-// mZeroCrossing.get(1).setXValue(end);
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/AFSK1200ZeroCrossingErrorDetectorChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/AFSK1200ZeroCrossingErrorDetectorChart.java
deleted file mode 100644
index 0d2b2449..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/AFSK1200ZeroCrossingErrorDetectorChart.java
+++ /dev/null
@@ -1,118 +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.gui.instrument.chart;
-
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.chart.LineChart;
-import javafx.scene.chart.NumberAxis;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class AFSK1200ZeroCrossingErrorDetectorChart extends LineChart
-{
- private final static Logger mLog = LoggerFactory.getLogger(AFSK1200ZeroCrossingErrorDetectorChart.class);
-
- private ObservableList> mCurrentSamples = FXCollections.observableArrayList();
- private Series mCurrentSampleSeries = new Series<>("Samples", mCurrentSamples);
-
- private ObservableList> mPreviousSamples = FXCollections.observableArrayList();
- private Series mPreviousSampleSeries = new Series<>("Samples", mPreviousSamples);
-
- private ObservableList> mDetected = FXCollections.observableArrayList();
- private Series mDetectedSeries = new Series<>("Detected", mDetected);
-
- private IInstrumentedAFSK1200Decoder mIInstrumentedAFSK1200Decoder;
-
- public AFSK1200ZeroCrossingErrorDetectorChart(IInstrumentedAFSK1200Decoder decoder, int length)
- {
- super(new NumberAxis("Samples", 0, length, 5),
- new NumberAxis("Value", -1.0, 1.0, 0.25));
-
- ObservableList observableList = FXCollections.observableArrayList(mCurrentSampleSeries,
- mPreviousSampleSeries, mDetectedSeries);
- setData(observableList);
-
- mIInstrumentedAFSK1200Decoder = decoder;
- decoder.getAFSK1200Decoder().getErrorDetector().timingError.addListener(new ErrorChangeListener());
- decoder.getBufferCountProperty().addListener(new ChangeListener()
- {
- @Override
- public void changed(ObservableValue observable, Object oldValue, Object newValue)
- {
- updateBuffer();
- }
- });
-
- for(int x = 0; x < length; x++)
- {
- Data sample = new Data<>(x, 0.0f);
- mCurrentSamples.add(sample);
- Data sample2 = new Data<>(x, 0.0f);
- mPreviousSamples.add(sample2);
- }
-
- Data detected1 = new Data<>(5, -0.25f);
- mDetected.add(detected1);
- Data detected2 = new Data<>(5, -0.75f);
- mDetected.add(detected2);
- }
-
- private void updateBuffer()
- {
- boolean[] samples = mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getErrorDetector().getBuffer();
-
- for(int x = 0; x < samples.length; x++)
- {
- Data sample = mCurrentSamples.get(x);
- sample.setYValue(samples[x] ? 0.7f : 0.3f);
- }
- }
-
- public class ErrorChangeListener implements ChangeListener
- {
- @Override
- public void changed(ObservableValue observable, Object oldValue, Object newValue)
- {
- float error = mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getErrorDetector().getError();
-
- boolean[] samples = mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getErrorDetector().getBuffer();
-
- for(int x = 0; x < samples.length; x++)
- {
- Data sample = mPreviousSamples.get(x);
- sample.setYValue(samples[x] ? -0.4f : -0.6f);
- }
-
- if(error == 0.0f)
- {
- Data detected1 = mDetected.get(0);
- detected1.setXValue(0.0f);
- Data detected2 = mDetected.get(1);
- detected2.setXValue(0.0f);
- }
- else
- {
- Data detected1 = mDetected.get(0);
- detected1.setXValue(mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getErrorDetector().getDetectedZeroCrossing());
- Data detected2 = mDetected.get(1);
- detected2.setXValue(mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getErrorDetector().getDetectedZeroCrossing());
- }
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/ComplexSampleLineChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/ComplexSampleLineChart.java
deleted file mode 100644
index ffe65c67..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/ComplexSampleLineChart.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.gui.instrument.chart;
-
-import io.github.dsheirer.buffer.ComplexCircularBuffer;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.Complex;
-import io.github.dsheirer.sample.complex.ComplexSampleListener;
-import io.github.dsheirer.sample.complex.ComplexSamples;
-import javafx.beans.property.IntegerProperty;
-import javafx.beans.property.SimpleIntegerProperty;
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.chart.LineChart;
-import javafx.scene.chart.NumberAxis;
-import javafx.scene.chart.XYChart;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ComplexSampleLineChart extends LineChart implements Listener, ComplexSampleListener
-{
- private final static Logger mLog = LoggerFactory.getLogger(ComplexSampleLineChart.class);
-
- private ComplexCircularBuffer mComplexCircularBuffer;
- private ComplexCircularBuffer mDemodulationCircularBuffer;
- private ObservableList> mISamples = FXCollections.observableArrayList();
- private ObservableList> mQSamples = FXCollections.observableArrayList();
- private IntegerProperty mLengthProperty = new SimpleIntegerProperty(40);
-
- public ComplexSampleLineChart(String label, int length, int samplesPerSymbol)
- {
- super(new NumberAxis(label, 0, length, 10),
- new NumberAxis("Value", -1.0, 1.0, 0.25));
-
- LineChart.Series iSampleSeries = new LineChart.Series<>("Inphase", mISamples);
- LineChart.Series qSampleSeries = new LineChart.Series<>("Quadrature", mQSamples);
- ObservableList> observableList =
- FXCollections.observableArrayList(iSampleSeries, qSampleSeries);
-
- setData(observableList);
- init(length, samplesPerSymbol);
- }
-
- public void setSamplesPerSymbol(int samplesPerSymbol)
- {
- mDemodulationCircularBuffer = new ComplexCircularBuffer(samplesPerSymbol);
- }
-
- private void init(int length, int samplesPerSymbol)
- {
- mLengthProperty.addListener(new ChangeListener()
- {
- @Override
- public void changed(ObservableValue extends Number> observable, Number oldValue, Number newValue)
- {
- mComplexCircularBuffer = new ComplexCircularBuffer(newValue.intValue());
- }
- });
- mComplexCircularBuffer = new ComplexCircularBuffer(length);
- mDemodulationCircularBuffer = new ComplexCircularBuffer(samplesPerSymbol);
- length().setValue(length);
-
- for(int x = 1; x <= length; x++)
- {
- mISamples.add(new Data(x, 0.0f));
- mQSamples.add(new Data(x, 0.0f));
- }
- }
-
- /**
- * Length of the x-axis for displaying samples
- */
- public IntegerProperty length()
- {
- return mLengthProperty;
- }
-
- @Override
- public void receive(ComplexSamples samples)
- {
- for(int x = 0; x < samples.i().length; x++)
- {
- receive(samples.i()[x], samples.q()[x]);
- }
- }
-
- @Override
- public void receive(float i, float q)
- {
- Complex sample = new Complex(i,q);
- sample.normalize();
- Complex previous = mDemodulationCircularBuffer.get(sample.copy());
- sample.multiply(previous.conjugate());
- mComplexCircularBuffer.put(sample);
- updateChart();
- }
-
- private void updateChart()
- {
- Complex[] samples = mComplexCircularBuffer.getAll();
-
- for(int x = 0; x < samples.length; x++)
- {
- Complex sample = samples[x];
-
- if(sample != null)
- {
- sample.normalize();
- mISamples.get(x).setYValue(sample.inphase());
- mQSamples.get(x).setYValue(sample.quadrature());
- }
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/DecodedSymbolChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/DecodedSymbolChart.java
deleted file mode 100644
index 3a416dfc..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/DecodedSymbolChart.java
+++ /dev/null
@@ -1,73 +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.gui.instrument.chart;
-
-import io.github.dsheirer.sample.Listener;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.chart.LineChart;
-import javafx.scene.chart.NumberAxis;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class DecodedSymbolChart extends LineChart implements Listener
-{
- private final static Logger mLog = LoggerFactory.getLogger(DecodedSymbolChart.class);
-
- private ObservableList> mSymbols = FXCollections.observableArrayList();
- private Series mSymbolSeries = new Series<>("Samples", mSymbols);
- private boolean[] mSymbolBuffer;
- private int mSymbolBufferPointer;
-
- public DecodedSymbolChart(int length)
- {
- super(new NumberAxis("Symbols", 0, length, 5),
- new NumberAxis("Value", -1.0, 1.0, 0.25));
-
- ObservableList observableList = FXCollections.observableArrayList(mSymbolSeries);
- setData(observableList);
-
- for(int x = 0; x < length; x++)
- {
- Data symbol = new Data<>(x, -0.5f);
- mSymbols.add(symbol);
- }
-
- mSymbolBuffer = new boolean[length];
- }
-
- @Override
- public void receive(Boolean symbol)
- {
- mSymbolBuffer[mSymbolBufferPointer++] = symbol;
- mSymbolBufferPointer %= mSymbolBuffer.length;
-
- update();
- }
-
- private void update()
- {
- for(int x = 0; x < mSymbolBuffer.length; x++)
- {
- Data symbol = mSymbols.get(x);
-
- int offset = x + mSymbolBufferPointer;
- offset %= mSymbolBuffer.length;
-
- symbol.setYValue(mSymbolBuffer[offset] ? 0.5f : -0.5f);
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/DoubleLineChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/DoubleLineChart.java
deleted file mode 100644
index ab661f59..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/DoubleLineChart.java
+++ /dev/null
@@ -1,91 +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.gui.instrument.chart;
-
-import io.github.dsheirer.buffer.DoubleCircularBuffer;
-import io.github.dsheirer.sample.Listener;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.chart.LineChart;
-import javafx.scene.chart.NumberAxis;
-import javafx.scene.chart.ValueAxis;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class DoubleLineChart extends LineChart implements Listener
-{
- private final static Logger mLog = LoggerFactory.getLogger(DoubleLineChart.class);
-
- private DoubleCircularBuffer mDoubleCircularBuffer;
- private ObservableList> mPhaseValues = FXCollections.observableArrayList();
-
- public DoubleLineChart(String seriesLabel, double min, double max, double tick, int length)
- {
- super(new NumberAxis(1, length, 2), new NumberAxis(min, max, tick));
-
- Series phaseSeries = new Series<>(seriesLabel, mPhaseValues);
- ObservableList> observableList = FXCollections.observableArrayList(phaseSeries);
-
- setData(observableList);
- init(length);
- }
-
- /**
- * Sets the minimum displayable value for the y axis
- * @param min
- */
- public void setMin(double min)
- {
- ((ValueAxis)getYAxis()).setLowerBound(min);
- }
-
- /**
- * Sets the maximum displayable value for the y axis
- * @param max
- */
- public void setMax(double max)
- {
- ((ValueAxis)getYAxis()).setUpperBound(max);
- }
-
- private void init(int length)
- {
- mDoubleCircularBuffer = new DoubleCircularBuffer(length);
-
- for(int x = 1; x <= length; x++)
- {
- mPhaseValues.add(new Data(x, 0.0));
- }
- }
-
- @Override
- public void receive(Double phase)
- {
- mDoubleCircularBuffer.put(phase);
-
- updateChart();
- }
-
- private void updateChart()
- {
- double[] values = mDoubleCircularBuffer.getAll();
-
- for(int x = 0; x < values.length; x++)
- {
- mPhaseValues.get(x).setYValue(values[x]);
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/EyeDiagramChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/EyeDiagramChart.java
deleted file mode 100644
index bc12a22b..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/EyeDiagramChart.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- *
- * * ******************************************************************************
- * * Copyright (C) 2014-2019 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * 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.gui.instrument.chart;
-
-import io.github.dsheirer.dsp.psk.SymbolDecisionData;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.Complex;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.chart.LineChart;
-import javafx.scene.chart.NumberAxis;
-import org.apache.commons.math3.util.FastMath;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class EyeDiagramChart extends LineChart implements Listener
-{
- private final static Logger mLog = LoggerFactory.getLogger(EyeDiagramChart.class);
-
- private ObservableList> mData = FXCollections.observableArrayList();
- private int mSeriesCount;
- private int mSeriesPointer;
- private int mSeriesLength;
-
- public EyeDiagramChart(int seriesCount, String legend)
- {
- super(new NumberAxis("Sample Point = 3", -1.0, 7.0, 1.0),
- new NumberAxis("Radians", -5.0, 5.0, 0.5));
-
- mSeriesCount = seriesCount;
- init();
- }
-
- private void init()
- {
- for(int x = 0; x < mSeriesCount; x++)
- {
- ObservableList> series = FXCollections.observableArrayList();
- mData.add(new Series(series));
- }
-
- setData(mData);
- }
-
- private ObservableList> getSeries(int series, int length)
- {
- ObservableList> seriesData = mData.get(series).getData();
-
- while(seriesData.size() > length)
- {
- seriesData.remove(0);
- }
-
- while(seriesData.size() < length)
- {
- seriesData.add(new Data<>(0.0,0.0f));
- }
-
- return seriesData;
- }
-
- private void checkChartLength(int length)
- {
- if(mSeriesLength != length)
- {
- ((NumberAxis)getXAxis()).setUpperBound(length);
- mSeriesLength = length;
- }
- }
-
- private float[] conditionData(Complex[] samples)
- {
- Float previousAngle = null;
- float[] corrected = new float[samples.length];
-
- int phaseRolloverIndex = -1;
-
- for(int x = 0; x < samples.length; x++)
- {
- corrected[x] = samples[x].angle();
-
- if(x > 0 && (FastMath.abs(corrected[x] - corrected[x - 1]) > FastMath.PI))
- {
- phaseRolloverIndex = x;
- }
- }
-
- if(phaseRolloverIndex >= 0)
- {
- for(int x = 0; x < phaseRolloverIndex; x++)
- {
- if(corrected[x] > 0)
- {
- corrected[x] -= 2 * FastMath.PI;
- }
- else
- {
- corrected[x] += 2 * FastMath.PI;
- }
- }
- }
-
- return corrected;
- }
-
- @Override
- public void receive(SymbolDecisionData symbolDecisionData)
- {
- Complex[] samples = symbolDecisionData.getSamples();
- int length = samples.length;
-
- ObservableList> iSeries = getSeries(mSeriesPointer++, length);
-// checkChartLength(length);
-
- if(mSeriesPointer >= mSeriesCount)
- {
- mSeriesPointer = 0;
- }
-
- float[] angles = conditionData(samples);
-
- for(int x = 0; x < samples.length; x++)
- {
- Data iDataPoint = iSeries.get(x);
- Complex sample = samples[x];
- iDataPoint.setXValue((double)x - symbolDecisionData.getSamplingPoint());
- iDataPoint.setYValue(angles[x]);
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/IInstrumentedAFSK1200Decoder.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/IInstrumentedAFSK1200Decoder.java
deleted file mode 100644
index 5308cd81..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/IInstrumentedAFSK1200Decoder.java
+++ /dev/null
@@ -1,30 +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.gui.instrument.chart;
-
-import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
-import io.github.dsheirer.message.IMessage;
-import io.github.dsheirer.sample.Listener;
-import javafx.beans.property.SimpleIntegerProperty;
-
-public interface IInstrumentedAFSK1200Decoder
-{
- SimpleIntegerProperty getBufferCountProperty();
-
- AFSK1200DecoderInstrumented getAFSK1200Decoder();
-
- void setMessageListener(Listener listener);
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/LTRNetSampleBufferChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/LTRNetSampleBufferChart.java
deleted file mode 100644
index fe898009..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/LTRNetSampleBufferChart.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2023 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.gui.instrument.chart;
-
-import io.github.dsheirer.module.decode.ltrnet.LTRNetDecoderInstrumented;
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.chart.LineChart;
-import javafx.scene.chart.NumberAxis;
-import javafx.scene.layout.StackPane;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class LTRNetSampleBufferChart extends LineChart
-{
- private final static Logger mLog = LoggerFactory.getLogger(LTRNetSampleBufferChart.class);
- private ObservableList> mSamples = FXCollections.observableArrayList();
- private Series mSampleSeries = new Series<>("Samples", mSamples);
-
- private ObservableList> mSamplePoints = FXCollections.observableArrayList();
- private Series mSamplePointSeries = new Series<>("Pointers", mSamplePoints);
-
- private ObservableList> mSymbolSamples = FXCollections.observableArrayList();
- private Series mSymbolSamplesSeries = new Series<>("Next Symbol Samples", mSymbolSamples);
-
- private ObservableList> mSymbol = FXCollections.observableArrayList();
- private Series mSymbolSeries = new Series<>("Previous Symbol", mSymbol);
-
- private ObservableList> mZeroCrossing = FXCollections.observableArrayList();
- private Series mZeroCrossingSeries = new Series<>("Zero Crossing", mZeroCrossing);
-
- private LTRNetDecoderInstrumented mLTRNetDecoderInstrumented;
-
- public LTRNetSampleBufferChart(LTRNetDecoderInstrumented decoder, int length)
- {
- super(new NumberAxis("Samples", 0, length, 5),
- new NumberAxis("Value", -1.0, 1.0, 0.25));
-
- ObservableList observableList = FXCollections.observableArrayList(mSampleSeries, mSamplePointSeries,
- mSymbolSamplesSeries, mSymbolSeries, mZeroCrossingSeries);
-
- setData(observableList);
-
- mLTRNetDecoderInstrumented = decoder;
- decoder.bufferCount.addListener(new BufferChangeListener());
-// decoder.getLTRDecoder().getErrorDetector().timingError.addListener(new ErrorChangeListener());
- }
-
- public void setBuffer(boolean[] buffer)
- {
- while(mSamples.size() < buffer.length)
- {
- Data sample = new Data<>(mSamples.size(), 0.0f);
- mSamples.add(sample);
-
- //Turn off the data point marker symbols - yes I know this is inefficient
- for(Data data: mSampleSeries.getData())
- {
- StackPane stackPane = (StackPane)data.getNode();
- stackPane.setVisible(false);
- }
- }
-
- for(int x = 0; x < buffer.length; x++)
- {
- Data sample = mSamples.get(x);
-
- sample.setYValue(buffer[x] ? 0.5f : -0.5f);
- }
- }
-
- public class BufferChangeListener implements ChangeListener
- {
- @Override
- public void changed(ObservableValue observable, Object oldValue, Object newValue)
- {
-// setBuffer(mLTRNetDecoderInstrumented.getLTRDecoder().getSampleBuffer().getDelayLine());
-
- while(mSymbol.size() < 2)
- {
- Data sample = new Data<>(0.0, -0.55);
- mSymbol.add(sample);
- }
-
- while(mZeroCrossing.size() < 2)
- {
- Data sample = new Data<>(0.0, -0.65);
- mZeroCrossing.add(sample);
- }
-
- while(mSamplePoints.size() < 2)
- {
- Data sample = new Data<>(0.0, -0.75);
- mSamplePoints.add(sample);
- }
-
- while(mSymbolSamples.size() < 2)
- {
- Data sample = new Data<>(0.0, -0.85);
- mSymbolSamples.add(sample);
- }
-
-// int pointer1 = mLTRNetDecoderInstrumented.getLTRDecoder().getSampleBuffer().getDelayLinePointer();
-// int pointer2 = mLTRNetDecoderInstrumented.getLTRDecoder().getSampleBuffer().getDelayLineSecondPointer();
-
-// mSamplePoints.get(0).setXValue(pointer1);
-// mSamplePoints.get(1).setXValue(pointer2);
-
-// float samplesRemaining = mLTRNetDecoderInstrumented.getLTRDecoder().getSampleBuffer().getMidSymbolSamplingPoint();
-// float samplesPerSymbol = mLTRNetDecoderInstrumented.getLTRDecoder().getSampleBuffer().getSamplesPerSymbol();
-
-// float start = pointer1 + samplesRemaining;
-// float end = start + samplesPerSymbol;
-
-// mSymbolSamples.get(0).setXValue(start);
-// mSymbolSamples.get(1).setXValue(end);
-
-// boolean symbol = mLTRNetDecoderInstrumented.getLTRDecoder().getSampleBuffer().getLastSymbol();
-// int symbolStart = mLTRNetDecoderInstrumented.getLTRDecoder().getSampleBuffer().getSymbolStart();
-// int symbolEnd = mLTRNetDecoderInstrumented.getLTRDecoder().getSampleBuffer().getSymbolEnd();
-
-// mSymbol.get(0).setXValue(symbolStart);
-// mSymbol.get(0).setYValue(symbol ? 0.55f : -0.55f);
-// mSymbol.get(1).setXValue(symbolEnd);
-// mSymbol.get(1).setYValue(symbol ? 0.55f : -0.55f);
- }
- }
-
- public class ErrorChangeListener implements ChangeListener
- {
- @Override
- public void changed(ObservableValue observable, Object oldValue, Object newValue)
- {
- while(mZeroCrossing.size() < 2)
- {
- Data sample = new Data<>(0.0, -0.65);
- mZeroCrossing.add(sample);
- }
-
-// int pointer1 = mLTRNetDecoderInstrumented.getLTRDecoder().getSampleBuffer().getDelayLinePointer();
-// int pointer2 = mLTRNetDecoderInstrumented.getLTRDecoder().getSampleBuffer().getDelayLineSecondPointer();
-
-// float zeroCrossingIdeal = mLTRNetDecoderInstrumented.getLTRDecoder().getErrorDetector().getZeroCrossingIdeal();
-// float detectedZeroCrossing = zeroCrossingIdeal - ((Number)newValue).floatValue();
-//
-// int reference = (zeroCrossingIdeal < pointer1 || detectedZeroCrossing < pointer1 ? pointer2 : pointer1);
-// reference--;
-//
-// float start = reference - zeroCrossingIdeal;
-// float end = reference - detectedZeroCrossing;
-//
-// mZeroCrossing.get(0).setXValue(start);
-// mZeroCrossing.get(1).setXValue(end);
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/PhaseLineChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/PhaseLineChart.java
deleted file mode 100644
index cdcaf2ad..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/PhaseLineChart.java
+++ /dev/null
@@ -1,73 +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.gui.instrument.chart;
-
-import io.github.dsheirer.buffer.DoubleCircularBuffer;
-import io.github.dsheirer.sample.Listener;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.chart.LineChart;
-import javafx.scene.chart.NumberAxis;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class PhaseLineChart extends LineChart implements Listener
-{
- private final static Logger mLog = LoggerFactory.getLogger(PhaseLineChart.class);
-
- private DoubleCircularBuffer mDoubleCircularBuffer;
- private ObservableList> mPhaseValues = FXCollections.observableArrayList();
-
- public PhaseLineChart(int length)
- {
- super(new NumberAxis("Time", 1, length, 2),
- new NumberAxis("Phase", -0.8, 0.8, 0.1));
-
- Series phaseSeries = new Series<>("PLL Phase Error", mPhaseValues);
- ObservableList> observableList = FXCollections.observableArrayList(phaseSeries);
-
- setData(observableList);
- init(length);
- }
-
- private void init(int length)
- {
- mDoubleCircularBuffer = new DoubleCircularBuffer(length);
-
- for(int x = 1; x <= length; x++)
- {
- mPhaseValues.add(new Data(x, 0.0));
- }
- }
-
- @Override
- public void receive(Double phase)
- {
- mDoubleCircularBuffer.put(phase);
-
- updateChart();
- }
-
- private void updateChart()
- {
- double[] values = mDoubleCircularBuffer.getAll();
-
- for(int x = 0; x < values.length; x++)
- {
- mPhaseValues.get(x).setYValue(values[x]);
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/RealSampleLineChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/RealSampleLineChart.java
deleted file mode 100644
index 1f3c2002..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/RealSampleLineChart.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.gui.instrument.chart;
-
-import io.github.dsheirer.buffer.FloatCircularBuffer;
-import io.github.dsheirer.sample.Listener;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.chart.LineChart;
-import javafx.scene.chart.NumberAxis;
-import javafx.scene.chart.XYChart;
-import javafx.scene.layout.StackPane;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RealSampleLineChart extends LineChart implements Listener
-{
- private final static Logger mLog = LoggerFactory.getLogger(RealSampleLineChart.class);
- private ObservableList> mSamples = FXCollections.observableArrayList();
- private Series mSampleSeries = new Series<>("Samples", mSamples);
- private FloatCircularBuffer mRealCircularBuffer;
-
- public RealSampleLineChart(int length, double tickUnit)
- {
- super(new NumberAxis("Samples", 0, length, tickUnit),
- new NumberAxis("Value", -1.0, 1.0, 0.25));
-
- ObservableList> observableList = FXCollections.observableArrayList(mSampleSeries);
-
- setData(observableList);
-
- init(length);
- }
-
- private void init(int length)
- {
- mRealCircularBuffer = new FloatCircularBuffer(length);
-
- for(int x = 0; x < length; x++)
- {
- Data sample = new Data<>(x, 0.0f);
- mSamples.add(sample);
- }
-
- //Turn off the data point marker symbols
- for(XYChart.Data data: mSampleSeries.getData())
- {
- StackPane stackPane = (StackPane)data.getNode();
- stackPane.setVisible(false);
- }
- }
-
- @Override
- public void receive(float[] buffer)
- {
- for(float sample: buffer)
- {
- mRealCircularBuffer.put(sample);
- }
-
- float[] bufferSamples = mRealCircularBuffer.getAll();
-
- for(int x = 0; x < bufferSamples.length; x++)
- {
- Data sample = mSamples.get(x);
- sample.setYValue(bufferSamples[x]);
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/SampleXYChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/SampleXYChart.java
deleted file mode 100644
index 83991a71..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/SampleXYChart.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.gui.instrument.chart;
-
-import eu.hansolo.fx.charts.ChartType;
-import eu.hansolo.fx.charts.PolarChart;
-import eu.hansolo.fx.charts.XYPane;
-import eu.hansolo.fx.charts.data.XYChartItem;
-import eu.hansolo.fx.charts.series.XYSeries;
-import io.github.dsheirer.buffer.ComplexCircularBuffer;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.Complex;
-import io.github.dsheirer.sample.complex.ComplexSamples;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.paint.Color;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class SampleXYChart extends PolarChart implements Listener
-{
- private static ObservableList sChartItemList = FXCollections.observableArrayList();
-
- static
- {
- sChartItemList.add(new XYChartItem(1, 1));
- sChartItemList.add(new XYChartItem(-1, -1));
- }
-
- private final static Logger mLog = LoggerFactory.getLogger(SampleXYChart.class);
- private ComplexCircularBuffer mCircularBuffer;
- private int mSampleCount;
-
- public SampleXYChart(int sampleCount, String title)
- {
- super(new XYPane<>(new XYSeries<>(sChartItemList, ChartType.POLAR)));
- mSampleCount = sampleCount;
- mCircularBuffer = new ComplexCircularBuffer(mSampleCount);
-
- getXYPane().setLowerBoundX(0);
- getXYPane().setUpperBoundX(1.0);
- getXYPane().setLowerBoundY(0);
- getXYPane().setUpperBoundY(1.0);
- }
-
- private void init()
- {
- }
-
- @Override
- public void receive(ComplexSamples buffer)
- {
- for(int x = 0; x < buffer.i().length; x++)
- {
- mCircularBuffer.put(new Complex(buffer.i()[x], buffer.q()[x]));
- }
-
- Complex[] complexSamples = mCircularBuffer.getAll();
-
- XYSeries series = getXYPane().getListOfSeries().get(0);
- series.setStroke(Color.BLUE);
-
- series.getItems().clear();
-
- for (Complex sample : complexSamples) {
- series.getItems().add(new XYChartItem(sample.polarAngleDegrees(), sample.magnitude(), Color.BLUE));
- }
-
- refresh();
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/SamplesPerSymbolChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/SamplesPerSymbolChart.java
deleted file mode 100644
index f9b95dd4..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/SamplesPerSymbolChart.java
+++ /dev/null
@@ -1,59 +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.gui.instrument.chart;
-
-import javafx.collections.ObservableList;
-
-public class SamplesPerSymbolChart extends DoubleLineChart
-{
- private double mFractionalSamplesPerSymbol;
- private double mPreviousSamplesPerSymbol;
-
- public SamplesPerSymbolChart(int length, double samplesPerSymbol)
- {
- super("Samples Per Symbol", -1.0, 1.0, 0.1, length);
- setSamplesPerSymbol(samplesPerSymbol);
- }
-
- public void setSamplesPerSymbol(double samplesPerSymbol)
- {
- mFractionalSamplesPerSymbol = samplesPerSymbol - ((int)samplesPerSymbol);
- mPreviousSamplesPerSymbol = samplesPerSymbol;
-
- ObservableList seriesList = getData();
- seriesList.get(0).setName("Samples Per Symbol:" + samplesPerSymbol);
- }
-
- @Override
- public void receive(Double samplesPerSymbol)
- {
- double delta = samplesPerSymbol - mPreviousSamplesPerSymbol - mFractionalSamplesPerSymbol;
-
- while(delta < (-1.0 + mFractionalSamplesPerSymbol))
- {
- delta++;
- }
-
- while(delta > 1.0)
- {
- delta--;
- }
-
- super.receive(delta);
-
- mPreviousSamplesPerSymbol = samplesPerSymbol;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/SymbolChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/SymbolChart.java
deleted file mode 100644
index d5ea1567..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/SymbolChart.java
+++ /dev/null
@@ -1,90 +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.gui.instrument.chart;
-
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.Complex;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.chart.NumberAxis;
-import javafx.scene.chart.ScatterChart;
-import javafx.scene.chart.XYChart;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class SymbolChart extends ScatterChart implements Listener
-{
- private final static Logger mLog = LoggerFactory.getLogger(SymbolChart.class);
-
- private ObservableList mCurrentPoints = FXCollections.observableArrayList();
-// private ObservableList mPreviousPoints = FXCollections.observableArrayList();
-// private ObservableList mOldestPoints = FXCollections.observableArrayList();
- private int mDataPointer;
- private int mHistory;
-
- /**
- * Symbol chart for plotting a series of constellation symbols over time. Maintains three history sets for
- * current, previous, and oldest symbols.
- *
- * @param history size for each of the history sets
- */
- public SymbolChart(int history)
- {
- super(new NumberAxis("I", -1.1, 1.1, 0.2),
- new NumberAxis("Q", -1.1, 1.1, 0.2));
-
- mHistory = history;
-
- for(int x = 0; x < mHistory; x++)
- {
- mCurrentPoints.add(new XYChart.Data<>(0.0, 0.0));
-// mPreviousPoints.add(new XYChart.Data<>(0.0, 0.0));
-// mOldestPoints.add(new XYChart.Data<>(0.0, 0.0));
- }
-
- ObservableList data = FXCollections.observableArrayList();
- data.add(new ScatterChart.Series("Constellation", mCurrentPoints));
-// data.add(new ScatterChart.Series("Previous", mPreviousPoints));
-// data.add(new ScatterChart.Series("Oldest", mOldestPoints));
-
- this.setData(data);
- }
-
- @Override
- public void receive(Complex complex)
- {
- //Transfer previous to oldest
-// XYChart.Data oldest = mOldestPoints.get(mDataPointer);
-// XYChart.Data previous = mPreviousPoints.get(mDataPointer);
- XYChart.Data current = mCurrentPoints.get(mDataPointer);
-
-// oldest.setXValue(previous.getXValue());
-// oldest.setYValue(previous.getYValue());
-//
-// previous.setXValue(current.getXValue());
-// previous.setYValue(current.getYValue());
-
- current.setXValue(complex.inphase());
- current.setYValue(complex.quadrature());
-
- mDataPointer++;
-
- if(mDataPointer >= mHistory)
- {
- mDataPointer = 0;
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/ZeroCrossingErrorDetectorChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/ZeroCrossingErrorDetectorChart.java
deleted file mode 100644
index 1ed84977..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/chart/ZeroCrossingErrorDetectorChart.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2023 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.gui.instrument.chart;
-
-import io.github.dsheirer.module.decode.ltrnet.LTRNetDecoderInstrumented;
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.chart.LineChart;
-import javafx.scene.chart.NumberAxis;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ZeroCrossingErrorDetectorChart extends LineChart
-{
- private final static Logger mLog = LoggerFactory.getLogger(ZeroCrossingErrorDetectorChart.class);
-
- private ObservableList> mCurrentSamples = FXCollections.observableArrayList();
- private Series mCurrentSampleSeries = new Series<>("Samples", mCurrentSamples);
-
- private ObservableList> mPreviousSamples = FXCollections.observableArrayList();
- private Series mPreviousSampleSeries = new Series<>("Samples", mPreviousSamples);
-
- private ObservableList> mIdeal = FXCollections.observableArrayList();
- private Series mIdealSeries = new Series<>("Ideal", mIdeal);
-
- private ObservableList> mDetected = FXCollections.observableArrayList();
- private Series mDetectedSeries = new Series<>("Detected", mDetected);
-
- private LTRNetDecoderInstrumented mLTRNetDecoderInstrumented;
-
- public ZeroCrossingErrorDetectorChart(LTRNetDecoderInstrumented decoder, int length)
- {
- super(new NumberAxis("Samples", 0, length, 5),
- new NumberAxis("Value", -1.0, 1.0, 0.25));
-
- ObservableList observableList = FXCollections.observableArrayList(mCurrentSampleSeries,
- mPreviousSampleSeries, mIdealSeries, mDetectedSeries);
- setData(observableList);
-
- mLTRNetDecoderInstrumented = decoder;
-// decoder.getLTRDecoder().getErrorDetector().timingError.addListener(new ErrorChangeListener());
- decoder.bufferCount.addListener(new ChangeListener()
- {
- @Override
- public void changed(ObservableValue observable, Object oldValue, Object newValue)
- {
- updateBuffer();
- }
- });
-
- for(int x = 0; x < length; x++)
- {
- Data sample = new Data<>(x, 0.0f);
- mCurrentSamples.add(sample);
- Data sample2 = new Data<>(x, 0.0f);
- mPreviousSamples.add(sample2);
- }
-
- Data ideal1 = new Data<>(5, -0.1f);
- mIdeal.add(ideal1);
- Data ideal2 = new Data<>(5, -0.9f);
- mIdeal.add(ideal2);
-
- Data detected1 = new Data<>(5, -0.25f);
- mDetected.add(detected1);
- Data detected2 = new Data<>(5, -0.75f);
- mDetected.add(detected2);
- }
-
- private void updateBuffer()
- {
-// boolean[] samples = mLTRNetDecoderInstrumented.getLTRDecoder().getErrorDetector().getBuffer();
-//
-// for(int x = 0; x < samples.length; x++)
-// {
-// Data sample = mCurrentSamples.get(x);
-// sample.setYValue(samples[x] ? 0.7f : 0.3f);
-// }
- }
-
- public class ErrorChangeListener implements ChangeListener
- {
- @Override
- public void changed(ObservableValue observable, Object oldValue, Object newValue)
- {
-// float error = mLTRNetDecoderInstrumented.getLTRDecoder().getErrorDetector().getError();
-//
-// boolean[] samples = mLTRNetDecoderInstrumented.getLTRDecoder().getErrorDetector().getBuffer();
-//
-// for(int x = 0; x < samples.length; x++)
-// {
-// Data sample = mPreviousSamples.get(x);
-// sample.setYValue(samples[x] ? -0.4f : -0.6f);
-// }
-//
-// Data ideal1 = mIdeal.get(0);
-// ideal1.setXValue(mLTRNetDecoderInstrumented.getLTRDecoder().getErrorDetector().getZeroCrossingIdeal());
-// Data ideal2 = mIdeal.get(1);
-// ideal2.setXValue(mLTRNetDecoderInstrumented.getLTRDecoder().getErrorDetector().getZeroCrossingIdeal());
-//
-// if(error == 0.0f)
-// {
-// Data detected1 = mDetected.get(0);
-// detected1.setXValue(0.0f);
-// Data detected2 = mDetected.get(1);
-// detected2.setXValue(0.0f);
-// }
-// else
-// {
-// Data detected1 = mDetected.get(0);
-// detected1.setXValue(mLTRNetDecoderInstrumented.getLTRDecoder().getErrorDetector().getDetectedZeroCrossing());
-// Data detected2 = mDetected.get(1);
-// detected2.setXValue(mLTRNetDecoderInstrumented.getLTRDecoder().getErrorDetector().getDetectedZeroCrossing());
-// }
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/AbstractAFSK1200Pane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/AbstractAFSK1200Pane.java
deleted file mode 100644
index beaf818c..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/AbstractAFSK1200Pane.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.gui.instrument.decoder;
-
-import io.github.dsheirer.gui.instrument.chart.AFSK1200SampleBufferChart;
-import io.github.dsheirer.gui.instrument.chart.AFSK1200ZeroCrossingErrorDetectorChart;
-import io.github.dsheirer.gui.instrument.chart.DecodedSymbolChart;
-import io.github.dsheirer.gui.instrument.chart.IInstrumentedAFSK1200Decoder;
-import io.github.dsheirer.gui.instrument.chart.RealSampleLineChart;
-import io.github.dsheirer.message.IMessage;
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.sample.Listener;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.Priority;
-import javafx.scene.layout.VBox;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public abstract class AbstractAFSK1200Pane extends RealDecoderPane
-{
- private final static Logger mLog = LoggerFactory.getLogger(AbstractAFSK1200Pane.class);
-
- private HBox mSampleChartBox;
- private RealSampleLineChart mRealSampleLineChart;
- private HBox mSymbolDecoderBox;
- private AFSK1200SampleBufferChart mSampleBufferChart;
- private AFSK1200ZeroCrossingErrorDetectorChart mZeroCrossingErrorDetectorChart;
- private DecodedSymbolChart mDecodedSymbolChart;
-
- private IInstrumentedAFSK1200Decoder mDecoder;
-
- public AbstractAFSK1200Pane(DecoderType decoderType)
- {
- super(decoderType);
- init();
- }
-
- private void init()
- {
- //This is force-cast without type checking ....
- addListener((Listener) getDecoder());
-
- addListener(getSampleLineChart());
-
- HBox.setHgrow(getSampleChartBox(), Priority.ALWAYS);
- HBox.setHgrow(getSymbolDecoderBox(), Priority.ALWAYS);
-
- VBox.setVgrow(getSampleChartBox(), Priority.ALWAYS);
- VBox.setVgrow(getSymbolDecoderBox(), Priority.ALWAYS);
-
- getSampleChartBox().setMaxWidth(Double.MAX_VALUE);
- getSymbolDecoderBox().setMaxWidth(Double.MAX_VALUE);
-
- getChildren().addAll(getSampleChartBox(), getSymbolDecoderBox());
-
- getDecoder().getAFSK1200Decoder().addListener(getDecodedSymbolChart());
-
- getDecoder().setMessageListener(new Listener()
- {
- @Override
- public void receive(IMessage message)
- {
- mLog.debug((message.isValid() ? "PASS " : "FAIL ") + message.toString());
- }
- });
- }
-
- protected abstract IInstrumentedAFSK1200Decoder getDecoder();
-
- private HBox getSampleChartBox()
- {
- if(mSampleChartBox == null)
- {
- mSampleChartBox = new HBox();
- mSampleChartBox.setMaxHeight(Double.MAX_VALUE);
-
- getSampleLineChart().setMaxWidth(Double.MAX_VALUE);
- getDecodedSymbolChart().setMaxWidth(Double.MAX_VALUE);
-
- HBox.setHgrow(getSampleLineChart(), Priority.ALWAYS);
- HBox.setHgrow(getDecodedSymbolChart(), Priority.ALWAYS);
-
- mSampleChartBox.getChildren().addAll(getSampleLineChart(), getDecodedSymbolChart());
- }
-
- return mSampleChartBox;
- }
-
- private RealSampleLineChart getSampleLineChart()
- {
- if(mRealSampleLineChart == null)
- {
- mRealSampleLineChart = new RealSampleLineChart(200, (10.0));
- }
-
- return mRealSampleLineChart;
- }
-
- private HBox getSymbolDecoderBox()
- {
- if(mSymbolDecoderBox == null)
- {
- mSymbolDecoderBox = new HBox();
- mSymbolDecoderBox.setMaxWidth(Double.MAX_VALUE);
-
- getSampleBufferChart().setMaxWidth(Double.MAX_VALUE);
- getZeroCrossingErrorDetectorChart().setMaxWidth(Double.MAX_VALUE);
-
- HBox.setHgrow(getSampleBufferChart(), Priority.ALWAYS);
- HBox.setHgrow(getZeroCrossingErrorDetectorChart(), Priority.ALWAYS);
-
- mSymbolDecoderBox.getChildren().addAll(getSampleBufferChart(), getZeroCrossingErrorDetectorChart());
- }
-
- return mSymbolDecoderBox;
- }
-
- private AFSK1200SampleBufferChart getSampleBufferChart()
- {
- if(mSampleBufferChart == null)
- {
- mSampleBufferChart = new AFSK1200SampleBufferChart(getDecoder(), 106);
- }
-
- return mSampleBufferChart;
- }
-
- private AFSK1200ZeroCrossingErrorDetectorChart getZeroCrossingErrorDetectorChart()
- {
- if(mZeroCrossingErrorDetectorChart == null)
- {
- mZeroCrossingErrorDetectorChart = new AFSK1200ZeroCrossingErrorDetectorChart(getDecoder(),
- getDecoder().getAFSK1200Decoder().getErrorDetector().getBuffer().length);
- }
-
- return mZeroCrossingErrorDetectorChart;
- }
-
- private DecodedSymbolChart getDecodedSymbolChart()
- {
- if(mDecodedSymbolChart == null)
- {
- mDecodedSymbolChart = new DecodedSymbolChart(50);
- }
-
- return mDecodedSymbolChart;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/ComplexDecoderPane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/ComplexDecoderPane.java
deleted file mode 100644
index acf71e4a..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/ComplexDecoderPane.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.gui.instrument.decoder;
-
-import io.github.dsheirer.buffer.INativeBuffer;
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.sample.Broadcaster;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.SampleType;
-import javafx.scene.text.Text;
-
-public class ComplexDecoderPane extends AbstractDecoderPane
-{
- private Broadcaster mBufferBroadcaster = new Broadcaster();
- private DecoderType mDecoderType;
-
- public ComplexDecoderPane(DecoderType decoderType)
- {
- mDecoderType = decoderType;
- }
-
- /**
- * Package private - used by factory class to create an empty pane
- */
- ComplexDecoderPane()
- {
- getChildren().add(new Text("Please select a decoder from the menu"));
- }
-
- @Override
- SampleType getSampleType()
- {
- return SampleType.COMPLEX;
- }
-
- @Override
- public void receive(INativeBuffer nativeBuffer)
- {
- mBufferBroadcaster.broadcast(nativeBuffer);
- }
-
- public void addListener(Listener listener)
- {
- mBufferBroadcaster.addListener(listener);
- }
-
- public void removeListener(Listener listener)
- {
- mBufferBroadcaster.removeListener(listener);
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/DecoderPaneFactory.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/DecoderPaneFactory.java
deleted file mode 100644
index 151b8de7..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/DecoderPaneFactory.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2024 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.gui.instrument.decoder;
-
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.p25.phase1.P25P1Decoder;
-import java.util.EnumSet;
-
-public class DecoderPaneFactory
-{
- private static final EnumSet SUPPORTED_DECODER_TYPES = EnumSet.of(
- DecoderType.P25_PHASE1,
- DecoderType.P25_PHASE2,
- DecoderType.FLEETSYNC2,
- DecoderType.LJ_1200,
- DecoderType.LTR_NET,
- DecoderType.MDC1200,
- DecoderType.MPT1327,
- DecoderType.TAIT_1200);
-
- /**
- * Creates a decoder pane for the decoder type
- */
- public static AbstractDecoderPane getDecoderPane(DecoderType decoderType)
- {
- switch(decoderType)
- {
- case FLEETSYNC2:
- return new Fleetsync2Pane();
- case LJ_1200:
- return new LJ1200Pane();
- case LTR_NET:
- return new LTRNetPane();
- case MDC1200:
- return new MDC1200Pane();
- case MPT1327:
- return new MPT1327Pane();
- case TAIT_1200:
- return new Tait1200Pane();
- case P25_PHASE1:
- throw new IllegalArgumentException("Use the getP25P1DecoderPane() method for P25 decoder type");
- case P25_PHASE2:
- return new P25Phase2HDQPSKPane();
- }
-
- return getDefaultPane();
- }
-
- /**
- * Creates a decoder pane for the P25 decoder type
- */
- public static AbstractDecoderPane getP25P1DecoderPane(P25P1Decoder.Modulation modulation)
- {
- switch(modulation)
- {
- case C4FM:
- return new P25Phase1C4FMPane();
- case CQPSK:
- return new P25Phase1LSMPane();
- }
-
- return getDefaultPane();
- }
-
- /**
- * Creates an empty decoder pane
- */
- public static AbstractDecoderPane getDefaultPane()
- {
- return new ComplexDecoderPane();
- }
-
- /**
- * Indicates if the decoder type is supported by this factory
- */
- public static boolean isSupported(DecoderType decoderType)
- {
- return SUPPORTED_DECODER_TYPES.contains(decoderType);
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/Fleetsync2Pane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/Fleetsync2Pane.java
deleted file mode 100644
index d37f97fb..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/Fleetsync2Pane.java
+++ /dev/null
@@ -1,43 +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.gui.instrument.decoder;
-
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.fleetsync2.Fleetsync2DecoderInstrumented;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class Fleetsync2Pane extends AbstractAFSK1200Pane
-{
- private final static Logger mLog = LoggerFactory.getLogger(Fleetsync2Pane.class);
-
- private Fleetsync2DecoderInstrumented mDecoder;
-
- public Fleetsync2Pane()
- {
- super(DecoderType.FLEETSYNC2);
- }
-
- protected Fleetsync2DecoderInstrumented getDecoder()
- {
- if(mDecoder == null)
- {
- mDecoder = new Fleetsync2DecoderInstrumented();
- }
-
- return mDecoder;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/LJ1200Pane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/LJ1200Pane.java
deleted file mode 100644
index ddeb01c5..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/LJ1200Pane.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * This program is distributed in the hope that it will be useful,
- * * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * * GNU General Public License for more details.
- * *
- * * You should have received a copy of the GNU General Public License
- * * along with this program. If not, see
- * * *****************************************************************************
- *
- *
- */
-package io.github.dsheirer.gui.instrument.decoder;
-
-import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.lj1200.LJ1200DecoderInstrumented;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class LJ1200Pane extends AbstractAFSK1200Pane
-{
- private final static Logger mLog = LoggerFactory.getLogger(LJ1200Pane.class);
-
- private LJ1200DecoderInstrumented mDecoder;
-
- public LJ1200Pane()
- {
- super(DecoderType.LJ_1200);
- }
-
- protected LJ1200DecoderInstrumented getDecoder()
- {
- if(mDecoder == null)
- {
- mDecoder = new LJ1200DecoderInstrumented();
- mDecoder.getTowerMessageFramer().setSyncDetectListener(new ISyncDetectListener()
- {
- @Override
- public void syncDetected(int bitErrors)
- {
- mLog.debug("Tower Sync Detected!");
- }
-
- @Override
- public void syncLost(int bitsProcessed)
- {
- //no-op
- }
- });
- mDecoder.getTransponderMessageFramer().setSyncDetectListener(new ISyncDetectListener()
- {
- @Override
- public void syncDetected(int bitErrors)
- {
- mLog.debug("Transponder Sync Detected!");
- }
-
- @Override
- public void syncLost(int bitsProcessed)
- {
- //no-op
- }
- });
- }
-
- return mDecoder;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/LTRNetPane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/LTRNetPane.java
deleted file mode 100644
index 667cc7f0..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/LTRNetPane.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2023 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.gui.instrument.decoder;
-
-import io.github.dsheirer.gui.instrument.chart.LTRNetSampleBufferChart;
-import io.github.dsheirer.gui.instrument.chart.RealSampleLineChart;
-import io.github.dsheirer.gui.instrument.chart.ZeroCrossingErrorDetectorChart;
-import io.github.dsheirer.message.IMessage;
-import io.github.dsheirer.message.MessageDirection;
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.ltrnet.DecodeConfigLTRNet;
-import io.github.dsheirer.module.decode.ltrnet.LTRNetDecoderInstrumented;
-import io.github.dsheirer.sample.Listener;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.Priority;
-import javafx.scene.layout.VBox;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class LTRNetPane extends RealDecoderPane
-{
- private final static Logger mLog = LoggerFactory.getLogger(LTRNetPane.class);
-
- private HBox mSampleChartBox;
- private RealSampleLineChart mRealSampleLineChart;
- private HBox mSymbolDecoderBox;
- private LTRNetSampleBufferChart mLTRNetSampleBufferChart;
- private ZeroCrossingErrorDetectorChart mZeroCrossingErrorDetectorChart;
-
- private LTRNetDecoderInstrumented mDecoder;
-
- public LTRNetPane()
- {
- super(DecoderType.LTR_NET);
- init();
- }
-
- private void init()
- {
- addListener(getDecoder());
- addListener(getSampleLineChart());
-
- HBox.setHgrow(getSampleChartBox(), Priority.ALWAYS);
- HBox.setHgrow(getSymbolDecoderBox(), Priority.ALWAYS);
-
- VBox.setVgrow(getSampleChartBox(), Priority.ALWAYS);
- VBox.setVgrow(getSymbolDecoderBox(), Priority.ALWAYS);
-
- getSampleChartBox().setMaxWidth(Double.MAX_VALUE);
- getSymbolDecoderBox().setMaxWidth(Double.MAX_VALUE);
-
- getChildren().addAll(getSampleChartBox(), getSymbolDecoderBox());
-
- }
-
- private LTRNetDecoderInstrumented getDecoder()
- {
- if(mDecoder == null)
- {
- DecodeConfigLTRNet config = new DecodeConfigLTRNet();
- config.setMessageDirection(MessageDirection.OSW);
- mDecoder = new LTRNetDecoderInstrumented(config);
- mDecoder.setMessageListener(new Listener()
- {
- @Override
- public void receive(IMessage message)
- {
- mLog.debug(message.toString());
- }
- });
- }
-
- return mDecoder;
- }
-
- private HBox getSampleChartBox()
- {
- if(mSampleChartBox == null)
- {
- mSampleChartBox = new HBox();
- mSampleChartBox.setMaxHeight(Double.MAX_VALUE);
-
- getSampleLineChart().setMaxWidth(Double.MAX_VALUE);
- HBox.setHgrow(getSampleLineChart(), Priority.ALWAYS);
-
- mSampleChartBox.getChildren().addAll(getSampleLineChart());
- }
-
- return mSampleChartBox;
- }
-
- private RealSampleLineChart getSampleLineChart()
- {
- if(mRealSampleLineChart == null)
- {
- mRealSampleLineChart = new RealSampleLineChart(500, (8000.0 / 300.0));
- }
-
- return mRealSampleLineChart;
- }
-
- private HBox getSymbolDecoderBox()
- {
- if(mSymbolDecoderBox == null)
- {
- mSymbolDecoderBox = new HBox();
- mSymbolDecoderBox.setMaxWidth(Double.MAX_VALUE);
-
- getSampleBufferChart().setMaxWidth(Double.MAX_VALUE);
- HBox.setHgrow(getSampleBufferChart(), Priority.ALWAYS);
-
- mSampleChartBox.getChildren().addAll(getSampleBufferChart(), getZeroCrossingErrorDetectorChart());
- }
-
- return mSymbolDecoderBox;
- }
-
- private LTRNetSampleBufferChart getSampleBufferChart()
- {
- if(mLTRNetSampleBufferChart == null)
- {
- mLTRNetSampleBufferChart = new LTRNetSampleBufferChart(getDecoder(), 106);
- }
-
- return mLTRNetSampleBufferChart;
- }
-
- private ZeroCrossingErrorDetectorChart getZeroCrossingErrorDetectorChart()
- {
- if(mZeroCrossingErrorDetectorChart == null)
- {
-// mZeroCrossingErrorDetectorChart = new ZeroCrossingErrorDetectorChart(getDecoder(),
-// getDecoder().getLTRDecoder().getErrorDetector().getBuffer().length);
- }
-
- return mZeroCrossingErrorDetectorChart;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/MDC1200Pane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/MDC1200Pane.java
deleted file mode 100644
index 8de00fc2..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/MDC1200Pane.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- *
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * This program is distributed in the hope that it will be useful,
- * * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * * GNU General Public License for more details.
- * *
- * * You should have received a copy of the GNU General Public License
- * * along with this program. If not, see
- * * *****************************************************************************
- *
- *
- */
-package io.github.dsheirer.gui.instrument.decoder;
-
-import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.mdc1200.MDCDecoderInstrumented;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class MDC1200Pane extends AbstractAFSK1200Pane
-{
- private final static Logger mLog = LoggerFactory.getLogger(MDC1200Pane.class);
-
- private MDCDecoderInstrumented mDecoder;
-
- public MDC1200Pane()
- {
- super(DecoderType.MDC1200);
- }
-
- protected MDCDecoderInstrumented getDecoder()
- {
- if(mDecoder == null)
- {
- mDecoder = new MDCDecoderInstrumented();
- mDecoder.getMessageFramer().setSyncDetectListener(new ISyncDetectListener()
- {
- @Override
- public void syncDetected(int bitErrors)
- {
- mLog.debug("Sync Detected!");
- }
-
- @Override
- public void syncLost(int bitsProcessed)
- {
- mLog.debug("Sync Lost!");
- }
- });
- }
-
- return mDecoder;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/MPT1327Pane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/MPT1327Pane.java
deleted file mode 100644
index b6e1ad1f..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/MPT1327Pane.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * This program is distributed in the hope that it will be useful,
- * * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * * GNU General Public License for more details.
- * *
- * * You should have received a copy of the GNU General Public License
- * * along with this program. If not, see
- * * *****************************************************************************
- *
- *
- */
-package io.github.dsheirer.gui.instrument.decoder;
-
-import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.mpt1327.MPT1327DecoderInstrumented;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class MPT1327Pane extends AbstractAFSK1200Pane
-{
- private final static Logger mLog = LoggerFactory.getLogger(MPT1327Pane.class);
-
- private MPT1327DecoderInstrumented mDecoder;
-
- public MPT1327Pane()
- {
- super(DecoderType.MPT1327);
- }
-
- protected MPT1327DecoderInstrumented getDecoder()
- {
- if(mDecoder == null)
- {
- mDecoder = new MPT1327DecoderInstrumented();
- mDecoder.getControlMessageFramer().setSyncDetectListener(new ISyncDetectListener()
- {
- @Override
- public void syncDetected(int bitErrors)
- {
-// mLog.debug("Control Sync Detected!");
- }
-
- @Override
- public void syncLost(int bitsProcessed)
- {
- //no-op
- }
- });
- mDecoder.getTrafficMessageFramer().setSyncDetectListener(new ISyncDetectListener()
- {
- @Override
- public void syncDetected(int bitErrors)
- {
-// mLog.debug("Traffic Sync Detected!");
- }
-
- @Override
- public void syncLost(int bitsProcessed)
- {
- //no-op
- }
- });
- }
-
- return mDecoder;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1C4FMPane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1C4FMPane.java
deleted file mode 100644
index deb7adfe..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1C4FMPane.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.gui.instrument.decoder;
-
-import io.github.dsheirer.gui.instrument.chart.ComplexSampleLineChart;
-import io.github.dsheirer.gui.instrument.chart.DoubleLineChart;
-import io.github.dsheirer.gui.instrument.chart.EyeDiagramChart;
-import io.github.dsheirer.gui.instrument.chart.PhaseLineChart;
-import io.github.dsheirer.gui.instrument.chart.SymbolChart;
-import io.github.dsheirer.message.IMessage;
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderC4FMInstrumented;
-import io.github.dsheirer.sample.Broadcaster;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.ComplexSamples;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.Priority;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Iterator;
-
-public class P25Phase1C4FMPane extends ComplexDecoderPane
-{
- private final static Logger mLog = LoggerFactory.getLogger(P25Phase1C4FMPane.class);
-
- private HBox mSampleChartBox;
- private ComplexSampleLineChart mSampleLineChart;
- private EyeDiagramChart mEyeDiagramChart;
- private HBox mDecoderChartBox;
- private SymbolChart mSymbolChart;
- private PhaseLineChart mPLLPhaseErrorLineChart;
- private DoubleLineChart mPLLFrequencyLineChart;
- private DoubleLineChart mSamplesPerSymbolLineChart;
- private Broadcaster mFilteredBufferBroadcaster = new Broadcaster();
- private P25P1DecoderC4FMInstrumented mDecoder = new P25P1DecoderC4FMInstrumented();
-
- public P25Phase1C4FMPane()
- {
- super(DecoderType.P25_PHASE1);
- init();
- }
-
- private void init()
- {
- addListener(nativeBuffer ->
- {
- Iterator iterator = nativeBuffer.iterator();
-
- while(iterator.hasNext())
- {
- getDecoder().receive(iterator.next());
- }
- });
-
- getDecoder().setFilteredBufferListener(mFilteredBufferBroadcaster);
- getDecoder().setComplexSymbolListener(getSymbolChart());
- getDecoder().setPLLPhaseErrorListener(getPLLPhaseErrorLineChart());
- getDecoder().setPLLFrequencyListener(getPLLFrequencyLineChart());
- getDecoder().setSymbolDecisionDataListener(getEyeDiagramChart());
- getDecoder().setSamplesPerSymbolListener(getSamplesPerSymbolLineChart());
- mFilteredBufferBroadcaster.addListener(getSampleLineChart());
-
- HBox.setHgrow(getSampleChartBox(), Priority.ALWAYS);
- HBox.setHgrow(getDecoderChartBox(), Priority.ALWAYS);
- getChildren().addAll(getSampleChartBox(), getDecoderChartBox());
-
- mDecoder.setMessageListener(new Listener()
- {
- @Override
- public void receive(IMessage message)
- {
- mLog.debug(message.toString());
- }
- });
-
- }
-
- @Override
- public void setSampleRate(double sampleRate)
- {
- mLog.debug("Configuring for sample rate: " + sampleRate);
-
- mDecoder.setSampleRate(sampleRate);
- double samplesPerSymbol = sampleRate / 4800.0;
-
- getSampleLineChart().setSamplesPerSymbol((int) samplesPerSymbol);
- }
-
- private P25P1DecoderC4FMInstrumented getDecoder()
- {
- return mDecoder;
- }
-
- private SymbolChart getSymbolChart()
- {
- if(mSymbolChart == null)
- {
- mSymbolChart = new SymbolChart(10);
- }
-
- return mSymbolChart;
- }
-
- private HBox getDecoderChartBox()
- {
- if(mDecoderChartBox == null)
- {
- mDecoderChartBox = new HBox();
- mDecoderChartBox.setMaxHeight(Double.MAX_VALUE);
- getSymbolChart().setMaxWidth(Double.MAX_VALUE);
- getPLLPhaseErrorLineChart().setMaxWidth(Double.MAX_VALUE);
- getPLLFrequencyLineChart().setMaxWidth(Double.MAX_VALUE);
- HBox.setHgrow(getSymbolChart(), Priority.ALWAYS);
- HBox.setHgrow(getPLLPhaseErrorLineChart(), Priority.ALWAYS);
- HBox.setHgrow(getPLLFrequencyLineChart(), Priority.ALWAYS);
- mDecoderChartBox.getChildren().addAll(getSymbolChart(), getPLLPhaseErrorLineChart(),
- getPLLFrequencyLineChart());
- }
-
- return mDecoderChartBox;
- }
-
- private HBox getSampleChartBox()
- {
- if(mSampleChartBox == null)
- {
- mSampleChartBox = new HBox();
- mSampleChartBox.setMaxHeight(Double.MAX_VALUE);
- getSampleLineChart().setMaxWidth(Double.MAX_VALUE);
- getEyeDiagramChart().setMaxWidth(Double.MAX_VALUE);
- getSamplesPerSymbolLineChart().setMaxWidth(Double.MAX_VALUE);
- HBox.setHgrow(getSampleLineChart(), Priority.ALWAYS);
- HBox.setHgrow(getEyeDiagramChart(), Priority.ALWAYS);
- HBox.setHgrow(getSamplesPerSymbolLineChart(), Priority.ALWAYS);
- mSampleChartBox.getChildren().addAll(getSampleLineChart(), getEyeDiagramChart(),
- getSamplesPerSymbolLineChart());
- }
-
- return mSampleChartBox;
- }
-
- private ComplexSampleLineChart getSampleLineChart()
- {
- if(mSampleLineChart == null)
- {
- mSampleLineChart = new ComplexSampleLineChart("Raw Samples", 100, 10);
- }
-
- return mSampleLineChart;
- }
-
- private EyeDiagramChart getEyeDiagramChart()
- {
- if(mEyeDiagramChart == null)
- {
- mEyeDiagramChart = new EyeDiagramChart(10, "Symbol: 3-4");
- }
-
- return mEyeDiagramChart;
- }
-
- private PhaseLineChart getPLLPhaseErrorLineChart()
- {
- if(mPLLPhaseErrorLineChart == null)
- {
- mPLLPhaseErrorLineChart = new PhaseLineChart(40);
- }
-
- return mPLLPhaseErrorLineChart;
- }
-
- private DoubleLineChart getPLLFrequencyLineChart()
- {
- if(mPLLFrequencyLineChart == null)
- {
- mPLLFrequencyLineChart = new DoubleLineChart("PLL Frequency", -500, 500, 50, 40);
- }
-
- return mPLLFrequencyLineChart;
- }
-
- private DoubleLineChart getSamplesPerSymbolLineChart()
- {
- if(mSamplesPerSymbolLineChart == null)
- {
- mSamplesPerSymbolLineChart = new DoubleLineChart("Sample Point", 9.5, 11.5, 0.1, 40);
- }
-
- return mSamplesPerSymbolLineChart;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1LSMPane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1LSMPane.java
deleted file mode 100644
index a5d95169..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1LSMPane.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.gui.instrument.decoder;
-
-import io.github.dsheirer.gui.instrument.chart.ComplexSampleLineChart;
-import io.github.dsheirer.gui.instrument.chart.DoubleLineChart;
-import io.github.dsheirer.gui.instrument.chart.EyeDiagramChart;
-import io.github.dsheirer.gui.instrument.chart.PhaseLineChart;
-import io.github.dsheirer.gui.instrument.chart.SamplesPerSymbolChart;
-import io.github.dsheirer.gui.instrument.chart.SymbolChart;
-import io.github.dsheirer.message.IMessage;
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderLSMInstrumented;
-import io.github.dsheirer.sample.Broadcaster;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.ComplexSamples;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.Priority;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Iterator;
-
-public class P25Phase1LSMPane extends ComplexDecoderPane
-{
- private final static Logger mLog = LoggerFactory.getLogger(P25Phase1LSMPane.class);
-
- private HBox mTopChartBox;
- private ComplexSampleLineChart mDifferentialDemodulatedSamplesChartBox;
- private EyeDiagramChart mEyeDiagramChart;
- private HBox mBottomChartBox;
- private SymbolChart mSymbolConstellationChart;
- private PhaseLineChart mPLLPhaseErrorLineChart;
- private DoubleLineChart mPLLFrequencyLineChart;
- private SamplesPerSymbolChart mSamplesPerSymbolLineChart;
- private Broadcaster mFilteredBufferBroadcaster = new Broadcaster();
- private P25P1DecoderLSMInstrumented mDecoder = new P25P1DecoderLSMInstrumented();
-
- public P25Phase1LSMPane()
- {
- super(DecoderType.P25_PHASE1);
- init();
- }
-
- private void init()
- {
- addListener(nativeBuffer ->
- {
- Iterator iterator = nativeBuffer.iterator();
-
- while(iterator.hasNext())
- {
- getDecoder().receive(iterator.next());
- }
- });
-
- getDecoder().setFilteredBufferListener(mFilteredBufferBroadcaster);
- getDecoder().setComplexSymbolListener(getSymbolConstellationChart());
- getDecoder().setPLLPhaseErrorListener(getPLLPhaseErrorLineChart());
- getDecoder().setPLLFrequencyListener(getPLLFrequencyLineChart());
- getDecoder().setSymbolDecisionDataListener(getEyeDiagramChart());
- getDecoder().setSamplesPerSymbolListener(getSamplesPerSymbolLineChart());
- mFilteredBufferBroadcaster.addListener(getDifferentialDemodulatedSamplesChartBox());
-
- HBox.setHgrow(getTopChartBox(), Priority.ALWAYS);
- HBox.setHgrow(getBottomChartBox(), Priority.ALWAYS);
- getChildren().addAll(getTopChartBox(), getBottomChartBox());
-
- mDecoder.setMessageListener(new Listener()
- {
- @Override
- public void receive(IMessage message)
- {
- mLog.debug(message.toString());
- }
- });
-
- }
-
- @Override
- public void setSampleRate(double sampleRate)
- {
- mLog.debug("Configuring for sample rate: " + sampleRate);
-
- mDecoder.setSampleRate(sampleRate);
- double samplesPerSymbol = sampleRate / 4800.0;
-
- getDifferentialDemodulatedSamplesChartBox().setSamplesPerSymbol((int) samplesPerSymbol);
- getSamplesPerSymbolLineChart().setSamplesPerSymbol(samplesPerSymbol);
- }
-
- private P25P1DecoderLSMInstrumented getDecoder()
- {
- return mDecoder;
- }
-
- private SymbolChart getSymbolConstellationChart()
- {
- if(mSymbolConstellationChart == null)
- {
- mSymbolConstellationChart = new SymbolChart(10);
- }
-
- return mSymbolConstellationChart;
- }
-
- private HBox getBottomChartBox()
- {
- if(mBottomChartBox == null)
- {
- mBottomChartBox = new HBox();
- mBottomChartBox.setMaxHeight(Double.MAX_VALUE);
- getSymbolConstellationChart().setMaxWidth(Double.MAX_VALUE);
- getPLLPhaseErrorLineChart().setMaxWidth(Double.MAX_VALUE);
- getPLLFrequencyLineChart().setMaxWidth(Double.MAX_VALUE);
- HBox.setHgrow(getSymbolConstellationChart(), Priority.ALWAYS);
- HBox.setHgrow(getPLLPhaseErrorLineChart(), Priority.ALWAYS);
- HBox.setHgrow(getPLLFrequencyLineChart(), Priority.ALWAYS);
- mBottomChartBox.getChildren().addAll(getSymbolConstellationChart(), getPLLPhaseErrorLineChart(),
- getPLLFrequencyLineChart());
- }
-
- return mBottomChartBox;
- }
-
- private HBox getTopChartBox()
- {
- if(mTopChartBox == null)
- {
- mTopChartBox = new HBox();
- mTopChartBox.setMaxHeight(Double.MAX_VALUE);
- getDifferentialDemodulatedSamplesChartBox().setMaxWidth(Double.MAX_VALUE);
- getEyeDiagramChart().setMaxWidth(Double.MAX_VALUE);
- getSamplesPerSymbolLineChart().setMaxWidth(Double.MAX_VALUE);
- HBox.setHgrow(getDifferentialDemodulatedSamplesChartBox(), Priority.ALWAYS);
- HBox.setHgrow(getEyeDiagramChart(), Priority.ALWAYS);
- HBox.setHgrow(getSamplesPerSymbolLineChart(), Priority.ALWAYS);
- mTopChartBox.getChildren().addAll(getDifferentialDemodulatedSamplesChartBox(), getEyeDiagramChart(),
- getSamplesPerSymbolLineChart());
- }
-
- return mTopChartBox;
- }
-
- private ComplexSampleLineChart getDifferentialDemodulatedSamplesChartBox()
- {
- if(mDifferentialDemodulatedSamplesChartBox == null)
- {
- mDifferentialDemodulatedSamplesChartBox = new ComplexSampleLineChart("Raw Samples", 100, 10);
- }
-
- return mDifferentialDemodulatedSamplesChartBox;
- }
-
- private EyeDiagramChart getEyeDiagramChart()
- {
- if(mEyeDiagramChart == null)
- {
- mEyeDiagramChart = new EyeDiagramChart(10, "Symbol/Eye Diagram");
- }
-
- return mEyeDiagramChart;
- }
-
- private PhaseLineChart getPLLPhaseErrorLineChart()
- {
- if(mPLLPhaseErrorLineChart == null)
- {
- mPLLPhaseErrorLineChart = new PhaseLineChart(40);
- }
-
- return mPLLPhaseErrorLineChart;
- }
-
- private DoubleLineChart getPLLFrequencyLineChart()
- {
- if(mPLLFrequencyLineChart == null)
- {
- mPLLFrequencyLineChart = new DoubleLineChart("PLL Frequency", -2500, 2500, 200, 40);
- }
-
- return mPLLFrequencyLineChart;
- }
-
- private SamplesPerSymbolChart getSamplesPerSymbolLineChart()
- {
- if(mSamplesPerSymbolLineChart == null)
- {
- mSamplesPerSymbolLineChart = new SamplesPerSymbolChart(40, 6.25);
- }
-
- return mSamplesPerSymbolLineChart;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase2HDQPSKPane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase2HDQPSKPane.java
deleted file mode 100644
index 9a017b02..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase2HDQPSKPane.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.gui.instrument.decoder;
-
-import io.github.dsheirer.gui.instrument.chart.ComplexSampleLineChart;
-import io.github.dsheirer.gui.instrument.chart.DoubleLineChart;
-import io.github.dsheirer.gui.instrument.chart.EyeDiagramChart;
-import io.github.dsheirer.gui.instrument.chart.PhaseLineChart;
-import io.github.dsheirer.gui.instrument.chart.SampleXYChart;
-import io.github.dsheirer.gui.instrument.chart.SymbolChart;
-import io.github.dsheirer.message.IMessage;
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.p25.phase2.DecodeConfigP25Phase2;
-import io.github.dsheirer.module.decode.p25.phase2.P25P2DecoderHDQPSKInstrumented;
-import io.github.dsheirer.sample.Broadcaster;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.ComplexSamples;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.Priority;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Iterator;
-
-public class P25Phase2HDQPSKPane extends ComplexDecoderPane
-{
- private final static Logger mLog = LoggerFactory.getLogger(P25Phase2HDQPSKPane.class);
-
- private HBox mSampleChartBox;
- private HBox mDecoderChartBox;
-
- private ComplexSampleLineChart mSampleLineChartRaw;
- private ComplexSampleLineChart mSampleLineChartPllCorrected;
- private EyeDiagramChart mEyeDiagramChart;
- private DoubleLineChart mSamplesPerSymbolLineChart;
-
- private SymbolChart mSymbolChart;
- private PhaseLineChart mPLLPhaseErrorLineChart;
- private DoubleLineChart mPLLFrequencyLineChart;
- private SampleXYChart mSampleXYChart;
-
-
- private Broadcaster mFilteredBufferBroadcaster = new Broadcaster();
- private P25P2DecoderHDQPSKInstrumented mDecoder = new P25P2DecoderHDQPSKInstrumented(new DecodeConfigP25Phase2());
-
- public P25Phase2HDQPSKPane()
- {
- super(DecoderType.P25_PHASE2);
- init();
- }
-
- private void init()
- {
- addListener(nativeBuffer ->
- {
- Iterator iterator = nativeBuffer.iterator();
-
- while(iterator.hasNext())
- {
- getDecoder().receive(iterator.next());
- }
- });
-
- getDecoder().getDemodulator().setFilteredGainAppliedComplexBufferListener(getSampleXYChart());
-
- getDecoder().setFilteredBufferListener(mFilteredBufferBroadcaster);
- getDecoder().setComplexSymbolListener(getSymbolChart());
- getDecoder().setPLLPhaseErrorListener(getPLLPhaseErrorLineChart());
- getDecoder().setPLLFrequencyListener(getPLLFrequencyLineChart());
- getDecoder().setSymbolDecisionDataListener(getEyeDiagramChart());
- getDecoder().setSamplesPerSymbolListener(getSamplesPerSymbolLineChart());
-
- //Listen for raw (uncorrected) samples
- mFilteredBufferBroadcaster.addListener(getSampleLineChartRaw());
-
- //Listen for PLL corrected samples
- getDecoder().getSampleBuffer().setSampleListener(getSampleLineChartPllCorrected());
-
- HBox.setHgrow(getSampleChartBox(), Priority.ALWAYS);
- HBox.setHgrow(getDecoderChartBox(), Priority.ALWAYS);
- getChildren().addAll(getSampleChartBox(), getDecoderChartBox());
-
- mDecoder.setMessageListener(new Listener()
- {
- @Override
- public void receive(IMessage message)
- {
- mLog.debug(message.toString());
- }
- });
-
- }
-
- @Override
- public void setSampleRate(double sampleRate)
- {
- mLog.debug("Configuring for sample rate: " + sampleRate);
-
- mDecoder.setSampleRate(sampleRate);
- double samplesPerSymbol = sampleRate / 4800.0;
-
- getSampleLineChartRaw().setSamplesPerSymbol((int) samplesPerSymbol);
- getDecoder().getSampleBuffer().setSampleListener(getSampleLineChartPllCorrected());
- getDecoder().getDemodulator().setFilteredGainAppliedComplexBufferListener(getSampleXYChart());
- }
-
- private P25P2DecoderHDQPSKInstrumented getDecoder()
- {
- return mDecoder;
- }
-
- private SymbolChart getSymbolChart()
- {
- if(mSymbolChart == null)
- {
- mSymbolChart = new SymbolChart(10);
- }
-
- return mSymbolChart;
- }
-
- private HBox getDecoderChartBox()
- {
- if(mDecoderChartBox == null)
- {
- mDecoderChartBox = new HBox();
- mDecoderChartBox.setMaxHeight(Double.MAX_VALUE);
- getSymbolChart().setMaxWidth(Double.MAX_VALUE);
- getPLLPhaseErrorLineChart().setMaxWidth(Double.MAX_VALUE);
- getPLLFrequencyLineChart().setMaxWidth(Double.MAX_VALUE);
- getSampleXYChart().setMaxWidth(Double.MAX_VALUE);
- HBox.setHgrow(getSymbolChart(), Priority.ALWAYS);
- HBox.setHgrow(getPLLPhaseErrorLineChart(), Priority.ALWAYS);
- HBox.setHgrow(getPLLFrequencyLineChart(), Priority.ALWAYS);
- HBox.setHgrow(getSampleXYChart(), Priority.ALWAYS);
- mDecoderChartBox.getChildren().addAll(getPLLPhaseErrorLineChart(), getPLLFrequencyLineChart(),
- getSymbolChart(), getSampleXYChart());
- }
-
- return mDecoderChartBox;
- }
-
- private HBox getSampleChartBox()
- {
- if(mSampleChartBox == null)
- {
- mSampleChartBox = new HBox();
- mSampleChartBox.setMaxHeight(Double.MAX_VALUE);
- getSampleLineChartRaw().setMaxWidth(Double.MAX_VALUE);
- getSampleLineChartPllCorrected().setMaxWidth(Double.MAX_VALUE);
- getEyeDiagramChart().setMaxWidth(Double.MAX_VALUE);
- getSamplesPerSymbolLineChart().setMaxWidth(Double.MAX_VALUE);
- HBox.setHgrow(getSampleLineChartRaw(), Priority.ALWAYS);
- HBox.setHgrow(getSampleLineChartPllCorrected(), Priority.ALWAYS);
- HBox.setHgrow(getEyeDiagramChart(), Priority.ALWAYS);
- HBox.setHgrow(getSamplesPerSymbolLineChart(), Priority.ALWAYS);
-
- mSampleChartBox.getChildren().addAll(getSampleLineChartRaw(), getSampleLineChartPllCorrected(),
- getEyeDiagramChart(), getSamplesPerSymbolLineChart());
- }
-
- return mSampleChartBox;
- }
-
- private ComplexSampleLineChart getSampleLineChartRaw()
- {
- if(mSampleLineChartRaw == null)
- {
- mSampleLineChartRaw = new ComplexSampleLineChart("Raw Samples", 100, 10);
- }
-
- return mSampleLineChartRaw;
- }
-
- private ComplexSampleLineChart getSampleLineChartPllCorrected()
- {
- if(mSampleLineChartPllCorrected == null)
- {
- mSampleLineChartPllCorrected = new ComplexSampleLineChart("PLL Corrected Samples", 100, 10);
- }
-
- return mSampleLineChartPllCorrected;
- }
-
- private EyeDiagramChart getEyeDiagramChart()
- {
- if(mEyeDiagramChart == null)
- {
- mEyeDiagramChart = new EyeDiagramChart(10, "Symbol: 3-4");
- }
-
- return mEyeDiagramChart;
- }
-
- private PhaseLineChart getPLLPhaseErrorLineChart()
- {
- if(mPLLPhaseErrorLineChart == null)
- {
- mPLLPhaseErrorLineChart = new PhaseLineChart(40);
- }
-
- return mPLLPhaseErrorLineChart;
- }
-
- private DoubleLineChart getPLLFrequencyLineChart()
- {
- if(mPLLFrequencyLineChart == null)
- {
- mPLLFrequencyLineChart = new DoubleLineChart("PLL Frequency", -500, 500, 50, 40);
- }
-
- return mPLLFrequencyLineChart;
- }
-
- private SampleXYChart getSampleXYChart()
- {
- if(mSampleXYChart == null)
- {
- mSampleXYChart = new SampleXYChart(100, "Samples");
- }
-
- return mSampleXYChart;
- }
-
- private DoubleLineChart getSamplesPerSymbolLineChart()
- {
- if(mSamplesPerSymbolLineChart == null)
- {
- mSamplesPerSymbolLineChart = new DoubleLineChart("Sample Point", 8.0, 10.0, 0.1, 40);
- }
-
- return mSamplesPerSymbolLineChart;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/RealDecoderPane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/RealDecoderPane.java
deleted file mode 100644
index 7bff926c..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/RealDecoderPane.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.gui.instrument.decoder;
-
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.sample.Broadcaster;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.SampleType;
-import javafx.scene.text.Text;
-
-public class RealDecoderPane extends AbstractDecoderPane
-{
- private Broadcaster mBufferBroadcaster = new Broadcaster();
- private DecoderType mDecoderType;
-
- public RealDecoderPane(DecoderType decoderType)
- {
- mDecoderType = decoderType;
- }
-
- /**
- * Package private - used by factory class to create an empty pane
- */
- RealDecoderPane()
- {
- getChildren().add(new Text("Please select a decoder from the menu"));
- }
-
- @Override
- SampleType getSampleType()
- {
- return SampleType.COMPLEX;
- }
-
- @Override
- public void receive(float[] buffer)
- {
- mBufferBroadcaster.broadcast(buffer);
- }
-
- public void addListener(Listener listener)
- {
- mBufferBroadcaster.addListener(listener);
- }
-
- public void removeListener(Listener listener)
- {
- mBufferBroadcaster.removeListener(listener);
- }
-
- public void setSampleRate(double sampleRate)
- {
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/Tait1200Pane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/Tait1200Pane.java
deleted file mode 100644
index 17833acf..00000000
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/Tait1200Pane.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * This program is distributed in the hope that it will be useful,
- * * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * * GNU General Public License for more details.
- * *
- * * You should have received a copy of the GNU General Public License
- * * along with this program. If not, see
- * * *****************************************************************************
- *
- *
- */
-package io.github.dsheirer.gui.instrument.decoder;
-
-import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
-import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.tait.Tait1200DecoderInstrumented;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class Tait1200Pane extends AbstractAFSK1200Pane
-{
- private final static Logger mLog = LoggerFactory.getLogger(Tait1200Pane.class);
-
- private Tait1200DecoderInstrumented mDecoder;
-
- public Tait1200Pane()
- {
- super(DecoderType.TAIT_1200);
- }
-
- protected Tait1200DecoderInstrumented getDecoder()
- {
- if(mDecoder == null)
- {
- mDecoder = new Tait1200DecoderInstrumented();
- mDecoder.getANIMessageFramer().setSyncDetectListener(new ISyncDetectListener()
- {
- @Override
- public void syncDetected(int bitErrors)
- {
- mLog.debug("ANI Sync Detected!");
- }
-
- @Override
- public void syncLost(int bitsProcessed)
- {
-
- }
- });
- mDecoder.getGPSMessageFramer().setSyncDetectListener(new ISyncDetectListener()
- {
- @Override
- public void syncDetected(int bitErrors)
- {
- mLog.debug("GPS Sync Detected!");
- }
-
- @Override
- public void syncLost(int bitsProcessed)
- {
-
- }
- });
- }
-
- return mDecoder;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/gui/playlist/channel/P25P1ConfigurationEditor.java b/src/main/java/io/github/dsheirer/gui/playlist/channel/P25P1ConfigurationEditor.java
index 63218562..c8e97e86 100644
--- a/src/main/java/io/github/dsheirer/gui/playlist/channel/P25P1ConfigurationEditor.java
+++ b/src/main/java/io/github/dsheirer/gui/playlist/channel/P25P1ConfigurationEditor.java
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
- * Copyright (C) 2014-2024 Dennis Sheirer
+ * Copyright (C) 2014-2025 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
@@ -27,7 +27,7 @@ import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.module.decode.p25.phase1.DecodeConfigP25Phase1;
-import io.github.dsheirer.module.decode.p25.phase1.P25P1Decoder;
+import io.github.dsheirer.module.decode.p25.phase1.Modulation;
import io.github.dsheirer.module.log.EventLogType;
import io.github.dsheirer.module.log.config.EventLogConfiguration;
import io.github.dsheirer.playlist.PlaylistManager;
@@ -332,7 +332,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
DecodeConfigP25Phase1 decodeConfig = (DecodeConfigP25Phase1)config;
getIgnoreDataCallsButton().setSelected(decodeConfig.getIgnoreDataCalls());
getTrafficChannelPoolSizeSpinner().getValueFactory().setValue(decodeConfig.getTrafficChannelPoolSize());
- if(decodeConfig.getModulation() == P25P1Decoder.Modulation.C4FM)
+ if(decodeConfig.getModulation() == Modulation.C4FM)
{
getC4FMToggleButton().setSelected(true);
getLSMToggleButton().setSelected(false);
@@ -366,7 +366,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
config.setIgnoreDataCalls(getIgnoreDataCallsButton().isSelected());
config.setTrafficChannelPoolSize(getTrafficChannelPoolSizeSpinner().getValue());
- config.setModulation(getC4FMToggleButton().isSelected() ? P25P1Decoder.Modulation.C4FM : P25P1Decoder.Modulation.CQPSK);
+ config.setModulation(getC4FMToggleButton().isSelected() ? Modulation.C4FM : Modulation.CQPSK);
getItem().setDecodeConfiguration(config);
}
diff --git a/src/main/java/io/github/dsheirer/gui/playlist/radioreference/FrequencyEditor.java b/src/main/java/io/github/dsheirer/gui/playlist/radioreference/FrequencyEditor.java
index cb48e837..66a5cf6e 100644
--- a/src/main/java/io/github/dsheirer/gui/playlist/radioreference/FrequencyEditor.java
+++ b/src/main/java/io/github/dsheirer/gui/playlist/radioreference/FrequencyEditor.java
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
- * Copyright (C) 2014-2022 Dennis Sheirer
+ * Copyright (C) 2014-2025 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
@@ -26,7 +26,7 @@ import io.github.dsheirer.module.decode.DecoderFactory;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.module.decode.nbfm.DecodeConfigNBFM;
import io.github.dsheirer.module.decode.p25.phase1.DecodeConfigP25Phase1;
-import io.github.dsheirer.module.decode.p25.phase1.P25P1Decoder;
+import io.github.dsheirer.module.decode.p25.phase1.Modulation;
import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.rrapi.type.Category;
@@ -36,6 +36,7 @@ import io.github.dsheirer.rrapi.type.SubCategory;
import io.github.dsheirer.service.radioreference.RadioReference;
import io.github.dsheirer.source.config.SourceConfigTuner;
import io.github.dsheirer.util.ThreadPool;
+import java.text.DecimalFormat;
import javafx.animation.FadeTransition;
import javafx.application.Platform;
import javafx.geometry.HPos;
@@ -53,8 +54,6 @@ import javafx.util.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.text.DecimalFormat;
-
public class FrequencyEditor extends VBox
{
private static final Logger mLog = LoggerFactory.getLogger(FrequencyEditor.class);
@@ -421,7 +420,7 @@ public class FrequencyEditor extends VBox
}
else if(decodeConfiguration instanceof DecodeConfigP25Phase1)
{
- ((DecodeConfigP25Phase1)decodeConfiguration).setModulation(P25P1Decoder.Modulation.C4FM);
+ ((DecodeConfigP25Phase1)decodeConfiguration).setModulation(Modulation.C4FM);
}
channel.setDecodeConfiguration(decodeConfiguration);
return channel;
diff --git a/src/main/java/io/github/dsheirer/gui/playlist/radioreference/SiteEditor.java b/src/main/java/io/github/dsheirer/gui/playlist/radioreference/SiteEditor.java
index 8119c988..30e01809 100644
--- a/src/main/java/io/github/dsheirer/gui/playlist/radioreference/SiteEditor.java
+++ b/src/main/java/io/github/dsheirer/gui/playlist/radioreference/SiteEditor.java
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
- * Copyright (C) 2014-2024 Dennis Sheirer
+ * Copyright (C) 2014-2025 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
@@ -30,7 +30,7 @@ import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.module.decode.dmr.DecodeConfigDMR;
import io.github.dsheirer.module.decode.dmr.channel.TimeslotFrequency;
import io.github.dsheirer.module.decode.p25.phase1.DecodeConfigP25Phase1;
-import io.github.dsheirer.module.decode.p25.phase1.P25P1Decoder;
+import io.github.dsheirer.module.decode.p25.phase1.Modulation;
import io.github.dsheirer.module.decode.p25.phase2.DecodeConfigP25Phase2;
import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters;
import io.github.dsheirer.playlist.PlaylistManager;
@@ -257,7 +257,7 @@ public class SiteEditor extends GridPane
{
if(p1config instanceof DecodeConfigP25Phase1)
{
- ((DecodeConfigP25Phase1)p1config).setModulation(P25P1Decoder.Modulation.CQPSK);
+ ((DecodeConfigP25Phase1)p1config).setModulation(Modulation.CQPSK);
}
}
return p1config;
diff --git a/src/main/java/io/github/dsheirer/gui/squelch/NoiseSquelchView.java b/src/main/java/io/github/dsheirer/gui/squelch/NoiseSquelchView.java
index 293a35cc..26ebb088 100644
--- a/src/main/java/io/github/dsheirer/gui/squelch/NoiseSquelchView.java
+++ b/src/main/java/io/github/dsheirer/gui/squelch/NoiseSquelchView.java
@@ -22,6 +22,7 @@ package io.github.dsheirer.gui.squelch;
import io.github.dsheirer.dsp.squelch.INoiseSquelchController;
import io.github.dsheirer.dsp.squelch.NoiseSquelch;
import io.github.dsheirer.dsp.squelch.NoiseSquelchState;
+import io.github.dsheirer.gui.symbol.ChannelView;
import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.util.ThreadPool;
@@ -72,7 +73,7 @@ import org.slf4j.LoggerFactory;
* 1 for an operating range of 1-6. The close slider uses a range of 0-5 that is combined with the open slider for a
* range of (open + 0) to (open + 5).
*/
-public class NoiseSquelchView extends VBox implements Listener
+public class NoiseSquelchView extends ChannelView implements Listener
{
private static final Logger LOGGER = LoggerFactory.getLogger(NoiseSquelchView.class);
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00");
@@ -129,7 +130,6 @@ public class NoiseSquelchView extends VBox implements Listener
+ * ****************************************************************************
+ */
+
+package io.github.dsheirer.gui.symbol;
+
+import javafx.scene.layout.VBox;
+
+/**
+ * Base class for channel viewer panel
+ */
+public class ChannelView extends VBox
+{
+ private boolean mShowing = false;
+
+ /**
+ * Constructs an instance.
+ */
+ public ChannelView()
+ {
+ }
+
+ /**
+ * Indicates if this panel is currently showing.
+ * @return true if showing.
+ */
+ protected boolean isShowing()
+ {
+ return mShowing;
+ }
+
+ /**
+ * Toggle the showing state to indicate when the user has selected to show this panel.
+ * @param showing true or false to disable the panel.
+ */
+ public void setShowing(boolean showing)
+ {
+ mShowing = showing;
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/gui/symbol/SymbolView.java b/src/main/java/io/github/dsheirer/gui/symbol/SymbolView.java
new file mode 100644
index 00000000..d2927a1f
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/gui/symbol/SymbolView.java
@@ -0,0 +1,133 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2025 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.gui.symbol;
+
+import io.github.dsheirer.module.decode.FeedbackDecoder;
+import io.github.dsheirer.sample.Listener;
+import java.util.Arrays;
+import javafx.application.Platform;
+import javafx.scene.chart.NumberAxis;
+import javafx.scene.chart.ScatterChart;
+import javafx.scene.chart.XYChart;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.VBox;
+
+/**
+ * Chart display for received QPSK symbols
+ */
+public class SymbolView extends ChannelView implements Listener
+{
+ private static final int SYMBOL_DISPLAY_COUNT = 4800;
+ private static final int SYMBOL_QUEUE_SIZE = SYMBOL_DISPLAY_COUNT / 40;
+ private final float[] mSymbolQueue = new float[SYMBOL_QUEUE_SIZE];
+ private int mSymbolQueuePointer = 0;
+ private int mChartSymbolPointer = 0;
+ private final NumberAxis mSymbolTiming = new NumberAxis();
+ private final NumberAxis mSymbolPhase = new NumberAxis(-Math.PI, Math.PI, Math.PI / 2);
+ private final XYChart.Series mSymbolSeries = new XYChart.Series<>();
+ private final ScatterChart mSymbolChart = new ScatterChart<>(mSymbolTiming, mSymbolPhase);
+ private FeedbackDecoder mFeedbackDecoder;
+
+ /**
+ * Constructs an instance
+ */
+ public SymbolView()
+ {
+ mSymbolSeries.setName("xx Demodulated Symbols");
+
+ for(int x = 0; x < SYMBOL_DISPLAY_COUNT; x++)
+ {
+ mSymbolSeries.getData().add(new XYChart.Data<>(x, 0));
+ }
+
+ mSymbolChart.getData().add(mSymbolSeries);
+ mSymbolChart.setMaxHeight(Double.MAX_VALUE);
+ mSymbolChart.setMaxWidth(Double.MAX_VALUE);
+ mSymbolChart.setAnimated(false);
+ VBox.setVgrow(mSymbolChart, Priority.ALWAYS);
+ getChildren().add(mSymbolChart);
+ }
+
+ /**
+ * Updates the chart axis label with the currently displayed protocol
+ * @param protocol that is being processed/displayed.
+ */
+ public void setProtocol(String protocol)
+ {
+ Platform.runLater(() -> mSymbolSeries.setName(protocol + " Demodulated Symbols"));
+ }
+
+ /**
+ * Registers the decoder with this view and this view then registers as a symbol listener on the decoder.
+ * @param feedbackDecoder for this view
+ */
+ public void setSymbolProvider(FeedbackDecoder feedbackDecoder)
+ {
+ removeSymbolProvider();
+
+ mFeedbackDecoder = feedbackDecoder;
+
+ if(mFeedbackDecoder != null)
+ {
+ mFeedbackDecoder.setSymbolListener(this);
+ }
+ }
+
+ /**
+ * Removes current symbol provider and unregisters this view from that provider.
+ */
+ public void removeSymbolProvider()
+ {
+ if(mFeedbackDecoder != null)
+ {
+ mFeedbackDecoder.removeSymbolListener();
+ }
+
+ mFeedbackDecoder = null;
+ }
+
+ @Override
+ public void receive(Float symbol)
+ {
+ if(isShowing())
+ {
+ mSymbolQueue[mSymbolQueuePointer++] = symbol;
+
+ //Flush the queued symbols to the chart when the queue is full
+ if(mSymbolQueuePointer == SYMBOL_QUEUE_SIZE)
+ {
+ float[] symbolDataCopy = Arrays.copyOf(mSymbolQueue, mSymbolQueue.length);
+
+ //Execute the chart data update on the JavaFX UI thread
+ Platform.runLater(() ->
+ {
+ for(float v : symbolDataCopy)
+ {
+ mSymbolSeries.getData().get(mChartSymbolPointer++).setYValue(v);
+ mChartSymbolPointer %= SYMBOL_DISPLAY_COUNT;
+ }
+
+ });
+
+ mSymbolQueuePointer = 0;
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/gui/viewer/P25P1Viewer.java b/src/main/java/io/github/dsheirer/gui/viewer/P25P1Viewer.java
index df082114..22257bde 100644
--- a/src/main/java/io/github/dsheirer/gui/viewer/P25P1Viewer.java
+++ b/src/main/java/io/github/dsheirer/gui/viewer/P25P1Viewer.java
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
- * Copyright (C) 2014-2024 Dennis Sheirer
+ * Copyright (C) 2014-2025 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
@@ -25,6 +25,7 @@ import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.channel.state.DecoderStateEvent;
import io.github.dsheirer.channel.state.SingleChannelState;
import io.github.dsheirer.controller.channel.Channel;
+import io.github.dsheirer.dsp.symbol.Dibit;
import io.github.dsheirer.identifier.IdentifierUpdateNotification;
import io.github.dsheirer.identifier.configuration.FrequencyConfigurationIdentifier;
import io.github.dsheirer.message.IMessage;
@@ -164,8 +165,9 @@ public class P25P1Viewer extends VBox
ThreadPool.CACHED.submit(() -> {
List messagePackages = new ArrayList<>();
- P25P1MessageFramer messageFramer = new P25P1MessageFramer(null, 9600);
+ P25P1MessageFramer messageFramer = new P25P1MessageFramer();
P25P1MessageProcessor messageProcessor = new P25P1MessageProcessor();
+
Broadcaster messageBroadcaster = new Broadcaster<>();
messageFramer.setListener(messageBroadcaster);
messageBroadcaster.addListener(messageProcessor);
@@ -229,7 +231,13 @@ public class P25P1Viewer extends VBox
while(reader.hasNext())
{
ByteBuffer buffer = reader.next();
- messageFramer.receive(buffer);
+ for(byte value : buffer.array())
+ {
+ for(int x = 0; x <= 3; x++)
+ {
+ messageFramer.processWithHardSyncDetect(Dibit.parse(value, x));
+ }
+ }
}
}
catch(Exception ioe)
diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/AbstractDecoderPane.java b/src/main/java/io/github/dsheirer/gui/viewer/symbol/ISymbolResultsListener.java
similarity index 67%
rename from src/main/java/io/github/dsheirer/gui/instrument/decoder/AbstractDecoderPane.java
rename to src/main/java/io/github/dsheirer/gui/viewer/symbol/ISymbolResultsListener.java
index f87c8c11..73bb3595 100644
--- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/AbstractDecoderPane.java
+++ b/src/main/java/io/github/dsheirer/gui/viewer/symbol/ISymbolResultsListener.java
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
- * Copyright (C) 2014-2022 Dennis Sheirer
+ * Copyright (C) 2014-2025 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
@@ -16,17 +16,13 @@
* along with this program. If not, see
* ****************************************************************************
*/
-package io.github.dsheirer.gui.instrument.decoder;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.SampleType;
-import javafx.scene.layout.VBox;
+package io.github.dsheirer.gui.viewer.symbol;
-public abstract class AbstractDecoderPane extends VBox implements Listener
+import java.util.concurrent.CountDownLatch;
+
+public interface ISymbolResultsListener
{
- abstract SampleType getSampleType();
-
- public void setSampleRate(double sampleRate)
- {
- }
+ void receive(double samplesPerSymbol, float[] rawI, float[] rawQ, float sampleGain, float pll,
+ double[] points, float[] symbols, CountDownLatch release);
}
diff --git a/src/main/java/io/github/dsheirer/gui/viewer/symbol/SymbolViewPanel.java b/src/main/java/io/github/dsheirer/gui/viewer/symbol/SymbolViewPanel.java
new file mode 100644
index 00000000..2377304d
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/gui/viewer/symbol/SymbolViewPanel.java
@@ -0,0 +1,255 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2025 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.gui.viewer.symbol;
+
+import io.github.dsheirer.dsp.filter.interpolator.LinearInterpolator;
+import java.util.concurrent.CountDownLatch;
+import javafx.application.Platform;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.chart.LineChart;
+import javafx.scene.chart.NumberAxis;
+import javafx.scene.chart.XYChart;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.VBox;
+
+/**
+ * JavaFX viewer application for visualizing sample buffers and detected sync patterns
+ */
+public class SymbolViewPanel extends VBox implements ISymbolResultsListener
+{
+ private static final double TWO_PI = Math.PI * 2.0;
+ private final NumberAxis mRawTiming = new NumberAxis();
+ private final NumberAxis mRawValue = new NumberAxis(-1.1, 1.1, .1);
+ private final NumberAxis mDemodulatedTiming = new NumberAxis();
+ private final NumberAxis mDemodulatedValue = new NumberAxis(-1.1, 1.1, .1);
+ private final NumberAxis mSymbolTiming = new NumberAxis();
+ private final NumberAxis mSymbolValue = new NumberAxis(-Math.PI, Math.PI, Math.PI / 4.0);
+ private final LineChart mRawChart = new LineChart<>(mRawTiming, mRawValue);
+ private final LineChart mDemodulatedChart = new LineChart<>(mDemodulatedTiming, mDemodulatedValue);
+ private final LineChart mSymbolChart = new LineChart<>(mSymbolTiming, mSymbolValue);
+ private final Button mReleaseButton = new Button("Next Symbol");
+ private final Label mDisplayText = new Label();
+ private CountDownLatch mRelease;
+
+ /**
+ * Constructs an instance
+ */
+ public SymbolViewPanel()
+ {
+ setPadding(new Insets(5));
+ mRawTiming.setLabel("Raw Sample Timing");
+ mRawValue.setLabel("Raw Sample Value (+/- 1.0)");
+ mDemodulatedTiming.setLabel("Demodulated Sample Timing");
+ mDemodulatedValue.setLabel("Demodulated Sample Value (+/- 1.0)");
+ mSymbolTiming.setLabel("Symbol Timing");
+ mSymbolValue.setLabel("Symbol Value (+/- PI)");
+
+ mReleaseButton.setOnAction(e -> {
+ if(mRelease != null)
+ {
+ mRelease.countDown();
+ mReleaseButton.setDisable(true);
+ }
+ });
+
+ mRawChart.setAnimated(false);
+ mDemodulatedChart.setAnimated(false);
+ mSymbolChart.setAnimated(false);
+
+ VBox.setVgrow(mRawChart, Priority.ALWAYS);
+ VBox.setVgrow(mDemodulatedChart, Priority.ALWAYS);
+ VBox.setVgrow(mSymbolChart, Priority.ALWAYS);
+
+ HBox buttons = new HBox();
+ buttons.setAlignment(Pos.BASELINE_LEFT);
+ buttons.setSpacing(10);
+ buttons.getChildren().addAll(mReleaseButton, mDisplayText);
+ VBox.setVgrow(buttons, Priority.NEVER);
+
+ getChildren().addAll(buttons, mRawChart, mDemodulatedChart, mSymbolChart);
+ }
+
+ @Override
+ public void receive(double samplesPerSymbol, float[] rawI, float[] rawQ, float sampleGain, float pll,
+ double[] points, float[] symbolSequence, CountDownLatch release)
+ {
+ mRelease = release;
+ mReleaseButton.setDisable(release == null);
+
+ Platform.runLater(() -> {
+ XYChart.Series rawSeriesI = new XYChart.Series<>();
+ rawSeriesI.setName("Raw Samples");
+ XYChart.Series rawSeriesQ = new XYChart.Series<>();
+ XYChart.Series rawTiming = new XYChart.Series<>();
+ XYChart.Series rawDecisionI = new XYChart.Series<>();
+ XYChart.Series rawDecisionQ = new XYChart.Series<>();
+ XYChart.Series demodulatedSeriesI = new XYChart.Series<>();
+ XYChart.Series demodulatedSeriesQ = new XYChart.Series<>();
+ XYChart.Series demodulatedTiming = new XYChart.Series<>();
+ XYChart.Series demodulatedDecisionI = new XYChart.Series<>();
+ XYChart.Series demodulatedDecisionQ = new XYChart.Series<>();
+
+ XYChart.Series symbolsRaw = new XYChart.Series<>();
+ symbolsRaw.setName("Symbols Raw");
+ XYChart.Series symbolsPLL = new XYChart.Series<>();
+ symbolsPLL.setName("Symbols PLL");
+ XYChart.Series symbolTiming = new XYChart.Series<>();
+ XYChart.Series symbolP3 = new XYChart.Series<>();
+ XYChart.Series symbolP1 = new XYChart.Series<>();
+ XYChart.Series symbolM1 = new XYChart.Series<>();
+ XYChart.Series symbolM3 = new XYChart.Series<>();
+ XYChart.Series symbolsWithPLL = new XYChart.Series<>();
+ XYChart.Series symbolsWithoutPLL = new XYChart.Series<>();
+
+ float pllI = (float)Math.cos(pll);
+ float pllQ = (float)Math.sin(pll);
+ float pllTemp = 0;
+
+ double spsMax = Math.ceil(samplesPerSymbol);
+ double fractional = spsMax - samplesPerSymbol;
+ for(int x = 0; x < rawI.length; x++)
+ {
+ rawSeriesI.getData().add(new XYChart.Data<>(x, rawI[x] * sampleGain));
+ rawSeriesQ.getData().add(new XYChart.Data<>(x, rawQ[x] * sampleGain));
+
+ if(x >= spsMax)
+ {
+ int offset = x - (int)spsMax;
+ float previousI = LinearInterpolator.calculate(rawI[offset] * sampleGain, rawI[offset + 1] * sampleGain, fractional);
+ float previousQ = LinearInterpolator.calculate(rawQ[offset] * sampleGain, rawQ[offset + 1] * sampleGain, fractional);
+ float currentI = rawI[x] * sampleGain;
+ float currentQ = rawQ[x] * sampleGain;
+ float demodulatedI = (previousI * currentI) - (-previousQ * currentQ);
+ float demodulatedQ = (previousI * currentQ) + (-previousQ * currentI);
+
+ //Rotate by the PLL
+ pllTemp = (demodulatedI * pllI) - (demodulatedQ * pllQ);
+ demodulatedQ = (demodulatedQ * pllI) + (demodulatedI * pllQ);
+ demodulatedI = pllTemp;
+
+ demodulatedSeriesI.getData().add(new XYChart.Data<>(x, demodulatedI));
+ demodulatedSeriesQ.getData().add(new XYChart.Data<>(x, demodulatedQ));
+ symbolsRaw.getData().add(new XYChart.Data<>(x, Math.atan2(demodulatedQ, demodulatedI)));
+// symbolsPLL.getData().add(new XYChart.Data<>(x, normalize(Math.atan2(demodulatedQ, demodulatedI) + pll)));
+ }
+ }
+
+ rawTiming.getData().add(new XYChart.Data<>(0, -1));
+ demodulatedTiming.getData().add(new XYChart.Data<>(0, -1));
+ symbolTiming.getData().add(new XYChart.Data<>(0, -Math.PI));
+
+ for(int x = 0; x < 3; x++)
+ {
+ rawTiming.getData().add(new XYChart.Data<>(points[x], -1));
+ rawTiming.getData().add(new XYChart.Data<>(points[x], 1));
+ rawTiming.getData().add(new XYChart.Data<>(points[x], -1));
+ demodulatedTiming.getData().add(new XYChart.Data<>(points[x], -1));
+ demodulatedTiming.getData().add(new XYChart.Data<>(points[x], 1));
+ demodulatedTiming.getData().add(new XYChart.Data<>(points[x], -1));
+ symbolTiming.getData().add(new XYChart.Data<>(points[x], -Math.PI));
+ symbolTiming.getData().add(new XYChart.Data<>(points[x], Math.PI));
+ symbolTiming.getData().add(new XYChart.Data<>(points[x], -Math.PI));
+ }
+
+ rawTiming.getData().add(new XYChart.Data<>(rawI.length - 1, -1));
+ demodulatedTiming.getData().add(new XYChart.Data<>(rawI.length - 1, -1));
+ symbolTiming.getData().add(new XYChart.Data<>(rawI.length - 1, -Math.PI));
+
+ rawDecisionI.getData().add(new XYChart.Data<>(points[0], points[3]));
+ rawDecisionI.getData().add(new XYChart.Data<>(points[1], points[4]));
+ rawDecisionI.getData().add(new XYChart.Data<>(points[2], points[5]));
+
+ rawDecisionQ.getData().add(new XYChart.Data<>(points[0], points[6]));
+ rawDecisionQ.getData().add(new XYChart.Data<>(points[1], points[7]));
+ rawDecisionQ.getData().add(new XYChart.Data<>(points[2], points[8]));
+
+ demodulatedDecisionI.getData().add(new XYChart.Data<>(points[0], points[9]));
+ demodulatedDecisionI.getData().add(new XYChart.Data<>(points[1], points[10]));
+ demodulatedDecisionI.getData().add(new XYChart.Data<>(points[2], points[11]));
+
+ demodulatedDecisionQ.getData().add(new XYChart.Data<>(points[0], points[12]));
+ demodulatedDecisionQ.getData().add(new XYChart.Data<>(points[1], points[13]));
+ demodulatedDecisionQ.getData().add(new XYChart.Data<>(points[2], points[14]));
+
+ symbolP3.getData().add(new XYChart.Data<>(0, 3 * Math.PI / 4));
+ symbolP1.getData().add(new XYChart.Data<>(0, Math.PI / 4));
+ symbolM1.getData().add(new XYChart.Data<>(0, -Math.PI / 4));
+ symbolM3.getData().add(new XYChart.Data<>(0, -3 * Math.PI / 4));
+ symbolP3.getData().add(new XYChart.Data<>(rawI.length - 1, 3 * Math.PI / 4));
+ symbolP1.getData().add(new XYChart.Data<>(rawI.length - 1, Math.PI / 4));
+ symbolM1.getData().add(new XYChart.Data<>(rawI.length - 1, -Math.PI / 4));
+ symbolM3.getData().add(new XYChart.Data<>(rawI.length - 1, -3 * Math.PI / 4));
+
+ symbolsWithPLL.getData().add((new XYChart.Data<>(points[0], symbolSequence[0])));
+// symbolsWithPLL.getData().add((new XYChart.Data<>(points[1], symbolSequence[1])));
+ symbolsWithPLL.getData().add((new XYChart.Data<>(points[2], symbolSequence[2])));
+// symbolsWithoutPLL.getData().add((new XYChart.Data<>(points[0], normalize(symbolSequence[0] - pll))));
+// symbolsWithoutPLL.getData().add((new XYChart.Data<>(points[1], normalize(symbolSequence[1] - pll))));
+// symbolsWithoutPLL.getData().add((new XYChart.Data<>(points[2], normalize(symbolSequence[2] - pll))));
+
+ mRawChart.getData().clear();
+ mRawChart.getData().add(rawSeriesI);
+ mRawChart.getData().add(rawSeriesQ);
+ mRawChart.getData().add(rawTiming);
+ mRawChart.getData().add(rawDecisionI);
+ mRawChart.getData().add(rawDecisionQ);
+ mDemodulatedChart.getData().clear();
+ mDemodulatedChart.getData().add(demodulatedSeriesI);
+ mDemodulatedChart.getData().add(demodulatedSeriesQ);
+ mDemodulatedChart.getData().add(demodulatedTiming);
+ mDemodulatedChart.getData().add(demodulatedDecisionI);
+ mDemodulatedChart.getData().add(demodulatedDecisionQ);
+ mSymbolChart.getData().clear();
+ mSymbolChart.getData().add(symbolsRaw);
+// mSymbolChart.getData().add(symbolsPLL);
+ mSymbolChart.getData().add(symbolTiming);
+ mSymbolChart.getData().add(symbolP3);
+ mSymbolChart.getData().add(symbolP1);
+ mSymbolChart.getData().add(symbolM1);
+ mSymbolChart.getData().add(symbolM3);
+ mSymbolChart.getData().add(symbolsWithPLL);
+// mSymbolChart.getData().add(symbolsWithoutPLL);
+ mDisplayText.setText("PLL: " + pll + " Sample Gain: " + sampleGain);
+ });
+ }
+
+ /**
+ * Normalizes the value in radians to the range of +/-(2 * PI)
+ * @param value to normalize
+ * @return normalized value.
+ */
+ private static double normalize(double value)
+ {
+ if(value > Math.PI)
+ {
+ return value - TWO_PI;
+ }
+ else if(value < -Math.PI)
+ {
+ return value + TWO_PI;
+ }
+
+ return value;
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/gui/viewer/symbol/SymbolViewerFX.java b/src/main/java/io/github/dsheirer/gui/viewer/symbol/SymbolViewerFX.java
new file mode 100644
index 00000000..ba858c0e
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/gui/viewer/symbol/SymbolViewerFX.java
@@ -0,0 +1,104 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2025 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.gui.viewer.symbol;
+
+import io.github.dsheirer.util.SwingUtils;
+import java.util.concurrent.CountDownLatch;
+import javafx.application.Platform;
+import javafx.embed.swing.JFXPanel;
+import javafx.scene.Scene;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.JFrame;
+
+/**
+ * Utility for viewing sync detection results
+ */
+public class SymbolViewerFX implements ISymbolResultsListener
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(SymbolViewerFX.class.getName());
+ private ISymbolResultsListener mListener;
+
+ public SymbolViewerFX()
+ {
+ initUI();
+ }
+
+ @Override
+ public void receive(double samplesPerSymbol, float[] rawI, float[] rawQ, float sampleGain, float pll,
+ double[] points, float[] symbols, CountDownLatch releasee)
+ {
+ if(mListener != null)
+ {
+ mListener.receive(samplesPerSymbol, rawI, rawQ, sampleGain, pll, points, symbols, releasee);
+ }
+ }
+
+ /**
+ * Initializes the viewer UI
+ */
+ private void initUI()
+ {
+ CountDownLatch latch = new CountDownLatch(1);
+
+ final JFXPanel fxPanel = new JFXPanel();
+ Platform.runLater(() -> {
+ Platform.setImplicitExit(false);
+ SymbolViewPanel viewer = new SymbolViewPanel();
+ mListener = viewer;
+ Scene scene = new Scene(viewer, 1400, 1000);
+
+// URL resource = getClass().getResource("/sdrtrunk_style.css");
+//
+// if(resource != null)
+// {
+// scene.getStylesheets().add(resource.toExternalForm());
+// }
+// else
+// {
+// LOGGER.warn("Can't find stylesheet resource for sdrtrunk");
+// }
+
+ fxPanel.setScene(scene);
+ fxPanel.setVisible(true);
+
+ JFrame frame = new JFrame();
+ frame.setTitle("Symbol Results Viewer");
+ frame.setContentPane(fxPanel);
+ frame.setSize(1400, 1400);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setLocationRelativeTo(null);
+ SwingUtils.run(() -> {
+ frame.setVisible(true);
+ latch.countDown();
+ });
+ });
+
+ try
+ {
+ latch.await();
+ }
+ catch(InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/sync/visualizer/ISyncResultsListener.java b/src/main/java/io/github/dsheirer/gui/viewer/sync/ISyncResultsListener.java
similarity index 78%
rename from src/main/java/io/github/dsheirer/module/decode/dmr/sync/visualizer/ISyncResultsListener.java
rename to src/main/java/io/github/dsheirer/gui/viewer/sync/ISyncResultsListener.java
index 4057002b..5c6c795c 100644
--- a/src/main/java/io/github/dsheirer/module/decode/dmr/sync/visualizer/ISyncResultsListener.java
+++ b/src/main/java/io/github/dsheirer/gui/viewer/sync/ISyncResultsListener.java
@@ -17,7 +17,7 @@
* ****************************************************************************
*/
-package io.github.dsheirer.module.decode.dmr.sync.visualizer;
+package io.github.dsheirer.gui.viewer.sync;
import java.util.concurrent.CountDownLatch;
@@ -32,8 +32,17 @@ public interface ISyncResultsListener
* @param sync pattern symbols (ideal)
* @param samples demodulated samples
* @param syncIntervals for timing of each symbol in the samples array
+ * @param equalizerBalance balance for the equalizer
+ * @param equalizerGain gain for the equalizer
* @param label to display in the UI
* @param release that pauses execution until the user acknowledges the displayed sync results. Decrement the latch to release.
*/
- void receive(float[] symbols, float[] sync, float[] samples, float[] syncIntervals, String label, CountDownLatch release);
+ void receive(float[] symbols, float[] sync, float[] samples, float[] syncIntervals, float equalizerBalance,
+ float equalizerGain, String label, CountDownLatch release);
+
+ /**
+ * Post a symbol value to the listener
+ * @param symbol value in range +/- PI
+ */
+ void symbol(float symbol);
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/sync/visualizer/SyncResultsViewer.java b/src/main/java/io/github/dsheirer/gui/viewer/sync/SyncResultsViewer.java
similarity index 75%
rename from src/main/java/io/github/dsheirer/module/decode/dmr/sync/visualizer/SyncResultsViewer.java
rename to src/main/java/io/github/dsheirer/gui/viewer/sync/SyncResultsViewer.java
index f2a0c3ed..d0302c4a 100644
--- a/src/main/java/io/github/dsheirer/module/decode/dmr/sync/visualizer/SyncResultsViewer.java
+++ b/src/main/java/io/github/dsheirer/gui/viewer/sync/SyncResultsViewer.java
@@ -17,13 +17,15 @@
* ****************************************************************************
*/
-package io.github.dsheirer.module.decode.dmr.sync.visualizer;
+package io.github.dsheirer.gui.viewer.sync;
import io.github.dsheirer.util.SwingUtils;
import java.util.concurrent.CountDownLatch;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.swing.JFrame;
@@ -32,6 +34,7 @@ import javax.swing.JFrame;
*/
public class SyncResultsViewer implements ISyncResultsListener
{
+ private static final Logger LOGGER = LoggerFactory.getLogger(SyncResultsViewer.class.getName());
private ISyncResultsListener mListener;
public SyncResultsViewer()
@@ -42,18 +45,28 @@ public class SyncResultsViewer implements ISyncResultsListener
/**
* View sync detection results.
* @param symbols that were detected
- * @param samples for the symbols
* @param sync that was detected
+ * @param samples for the symbols
* @param syncIntervals symbol timing interval pointers into the I/Q sample arrays
* @param label to display to the user
* @param release latch to release via the UI when done viewing these results
*/
@Override
- public void receive(float[] symbols, float[] sync, float[] samples, float[] syncIntervals, String label, CountDownLatch release)
+ public void receive(float[] symbols, float[] sync, float[] samples, float[] syncIntervals, float equalizerBalance,
+ float equalizerGain, String label, CountDownLatch release)
{
if(mListener != null)
{
- mListener.receive(symbols, samples, sync, syncIntervals, label, release);
+ mListener.receive(symbols, samples, sync, syncIntervals, equalizerBalance, equalizerGain, label, release);
+ }
+ }
+
+ @Override
+ public void symbol(float symbol)
+ {
+ if(mListener != null)
+ {
+ mListener.symbol(symbol);
}
}
@@ -69,14 +82,27 @@ public class SyncResultsViewer implements ISyncResultsListener
Platform.setImplicitExit(false);
SyncVisualizer syncVisualizer = new SyncVisualizer();
mListener = syncVisualizer;
+
Scene scene = new Scene(syncVisualizer, 1400, 1000);
+
+// URL resource = getClass().getResource("/sdrtrunk_style.css");
+//
+// if(resource != null)
+// {
+// scene.getStylesheets().add(resource.toExternalForm());
+// }
+// else
+// {
+// LOGGER.warn("Can't find stylesheet resource for sdrtrunk");
+// }
+
fxPanel.setScene(scene);
fxPanel.setVisible(true);
JFrame frame = new JFrame();
frame.setTitle("Sync Results Viewer");
frame.setContentPane(fxPanel);
- frame.setSize(1400, 1000);
+ frame.setSize(1400, 1400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
SwingUtils.run(() -> {
diff --git a/src/main/java/io/github/dsheirer/gui/viewer/sync/SyncVisualizer.java b/src/main/java/io/github/dsheirer/gui/viewer/sync/SyncVisualizer.java
new file mode 100644
index 00000000..636c2973
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/gui/viewer/sync/SyncVisualizer.java
@@ -0,0 +1,218 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2025 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.gui.viewer.sync;
+
+import java.util.concurrent.CountDownLatch;
+import javafx.application.Platform;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.chart.LineChart;
+import javafx.scene.chart.NumberAxis;
+import javafx.scene.chart.ScatterChart;
+import javafx.scene.chart.XYChart;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.VBox;
+
+/**
+ * JavaFX viewer application for visualizing sample buffers and detected sync patterns
+ */
+public class SyncVisualizer extends VBox implements ISyncResultsListener
+{
+ private static final int SYMBOL_CHART_SERIES_COUNT = 2000;
+ private static final float SYMBOL = (float) (Math.PI / 4.0);
+ private final NumberAxis mConstellationI = new NumberAxis();
+ private final NumberAxis mConstellationQ = new NumberAxis();
+ private final NumberAxis mSampleTiming = new NumberAxis();
+ private final NumberAxis mSamplePhase = new NumberAxis(-3.5, 3.5, .5);
+ private final NumberAxis mSymbolTiming = new NumberAxis();
+ private final NumberAxis mSymbolPhase = new NumberAxis(-Math.PI, Math.PI, Math.PI / 2);
+ private final XYChart.Series mSymbolSeries = new XYChart.Series<>();
+ private final XYChart.Series mSymbolSeriesMarker = new XYChart.Series<>();
+ private final ScatterChart mConstellationChart = new ScatterChart<>(mConstellationI, mConstellationQ);
+ private final LineChart mSampleChart = new LineChart<>(mSampleTiming, mSamplePhase);
+ private final ScatterChart mSymbolChart = new ScatterChart<>(mSymbolTiming, mSymbolPhase);
+
+ private final NumberAxis mEqualizerHistoryAxis = new NumberAxis();
+ private final NumberAxis mEqualizerValueAxis = new NumberAxis(-1.5, 1.5, .1);
+ private final LineChart mEqualizerChart = new LineChart<>(mEqualizerHistoryAxis, mEqualizerValueAxis);
+ private int mEqualizerPointer = 0;
+ private int mEqualizerHistorySize = 40;
+ private float[] mEqualizerBalanceHistory = new float[mEqualizerHistorySize];
+ private float[] mEqualizerGainHistory = new float[mEqualizerHistorySize];
+
+ private final Button mReleaseButton = new Button("Next Sync");
+ private final Label mPatternLabel = new Label();
+ private CountDownLatch mRelease;
+ private int mSymbolPointer = 0;
+
+ /**
+ * Constructs an instance
+ */
+ public SyncVisualizer()
+ {
+ setPadding(new Insets(5));
+ mConstellationI.setLabel("Constellation - Inphase");
+ mConstellationQ.setLabel("Quadrature");
+ mSampleTiming.setLabel("Sample Timing");
+ mSamplePhase.setLabel("Sample Phase (+/- PI)");
+
+ mReleaseButton.setOnAction(e -> {
+ if(mRelease != null)
+ {
+ mRelease.countDown();
+ mReleaseButton.setDisable(true);
+ }
+ });
+
+ mConstellationChart.setPrefSize(400, 400);
+ mConstellationChart.setAnimated(false);
+ mSampleChart.setAnimated(false);
+ mSymbolChart.setAnimated(false);
+ mSymbolChart.setId("symbol-chart");
+ mEqualizerChart.setAnimated(false);
+
+ mEqualizerValueAxis.setLabel("Value");
+ mEqualizerHistoryAxis.setLabel("Equalizer");
+
+ HBox hbox = new HBox();
+ hbox.getChildren().add(mConstellationChart);
+ HBox.setHgrow(mEqualizerChart, Priority.ALWAYS);
+ hbox.getChildren().add(mEqualizerChart);
+ // VBox.setVgrow(hbox, Priority.ALWAYS);
+
+ VBox.setVgrow(mSampleChart, Priority.ALWAYS);
+ VBox.setVgrow(mSymbolChart, Priority.ALWAYS);
+
+ HBox buttons = new HBox();
+ buttons.setAlignment(Pos.BASELINE_LEFT);
+ buttons.setSpacing(10);
+ buttons.getChildren().addAll(mReleaseButton, mPatternLabel);
+ VBox.setVgrow(buttons, Priority.NEVER);
+
+ //Load the symbol chart with symbols
+ mSymbolSeries.setName("Symbols");
+ for(int x = 0; x < SYMBOL_CHART_SERIES_COUNT; x++)
+ {
+ mSymbolSeries.getData().add(new XYChart.Data<>(x, 0));
+ }
+ mSymbolChart.getData().add(mSymbolSeries);
+ float pi_4 = (float)Math.PI / 4f;
+ mSymbolSeriesMarker.getData().add(new XYChart.Data<>(0, 3f * pi_4));
+ mSymbolSeriesMarker.getData().add(new XYChart.Data<>(0, pi_4));
+ mSymbolSeriesMarker.getData().add(new XYChart.Data<>(0, 0));
+ mSymbolSeriesMarker.getData().add(new XYChart.Data<>(0, -pi_4));
+ mSymbolSeriesMarker.getData().add(new XYChart.Data<>(0, -3 * pi_4));
+ mSymbolChart.getData().add(mSymbolSeriesMarker);
+ getChildren().addAll(buttons, hbox, mSampleChart, mSymbolChart);
+ }
+
+ @Override
+ public void symbol(float symbol)
+ {
+ for(XYChart.Data data : mSymbolSeriesMarker.getData())
+ {
+ data.setXValue(mSymbolPointer);
+ }
+ mSymbolSeries.getData().get(mSymbolPointer++).setYValue(symbol);
+ mSymbolPointer %= SYMBOL_CHART_SERIES_COUNT;
+ }
+
+ @Override
+ public void receive(float[] symbols, float[] samples, float[] sync, float[] syncIntervals, float equalizerBalance, float equalizerGain, String label, CountDownLatch latch)
+ {
+ mRelease = latch;
+ mReleaseButton.setDisable(latch == null);
+
+ mEqualizerBalanceHistory[mEqualizerPointer] = equalizerBalance;
+ mEqualizerGainHistory[mEqualizerPointer++] = (equalizerGain - 1.0f);
+ mEqualizerPointer %= mEqualizerHistorySize;
+ //Clear the next/upcoming values to give visual indication of where we're at.
+ mEqualizerBalanceHistory[mEqualizerPointer] = 0f;
+ mEqualizerGainHistory[mEqualizerPointer] = 0f;
+
+ Platform.runLater(() -> {
+ XYChart.Series constellationIdeal = new XYChart.Series<>();
+ constellationIdeal.setName("Ideal");
+ float PI_4 = (float) (Math.PI / 4);
+ constellationIdeal.getData().add(new XYChart.Data<>(PI_4, PI_4));
+ constellationIdeal.getData().add(new XYChart.Data<>(PI_4, -PI_4));
+ constellationIdeal.getData().add(new XYChart.Data<>(-PI_4, PI_4));
+ constellationIdeal.getData().add(new XYChart.Data<>(-PI_4, -PI_4));
+ constellationIdeal.getData().add(new XYChart.Data<>(1, 0));
+ constellationIdeal.getData().add(new XYChart.Data<>(-1, 0));
+ constellationIdeal.getData().add(new XYChart.Data<>(0, 1));
+ constellationIdeal.getData().add(new XYChart.Data<>(0, -1));
+
+ mConstellationChart.getData().clear();
+ mConstellationChart.getData().add(constellationIdeal);
+
+ XYChart.Series constellation = new XYChart.Series<>();
+ constellation.setName("Decoded");
+
+ for(int x = 0; x < symbols.length; x++)
+ {
+ constellation.getData().add(new XYChart.Data<>(Math.cos(symbols[x]), Math.sin(symbols[x])));
+ }
+
+ mConstellationChart.getData().add(constellation);
+
+ XYChart.Series sampleSeries = new XYChart.Series<>();
+ sampleSeries.setName("Demodulated Samples");
+
+ for(int x = 0; x < samples.length; x++)
+ {
+ sampleSeries.getData().add(new XYChart.Data<>(x, samples[x]));
+ }
+
+ mSampleChart.getData().clear();
+ mSampleChart.getData().add(sampleSeries);
+
+ XYChart.Series patternSeries = new XYChart.Series<>();
+ patternSeries.setName("Ideal Sync Pattern");
+
+ for(int x = 0; x < sync.length; x++)
+ {
+ patternSeries.getData().add(new XYChart.Data<>(syncIntervals[x], sync[x]));
+ }
+
+ mSampleChart.getData().add(patternSeries);
+
+ mPatternLabel.setText(label);
+ mEqualizerChart.getData().clear();
+
+ XYChart.Series balanceSeries = new XYChart.Series<>();
+ balanceSeries.setName("Balance");
+ XYChart.Series gainSeries = new XYChart.Series<>();
+ gainSeries.setName("Gain (Value minus 1.0)");
+
+ for(int x = 0; x < mEqualizerHistorySize; x++)
+ {
+ balanceSeries.getData().add(new XYChart.Data<>(x, mEqualizerBalanceHistory[x]));
+ gainSeries.getData().add(new XYChart.Data<>(x, mEqualizerGainHistory[x]));
+ }
+
+ mEqualizerChart.getData().add(balanceSeries);
+ mEqualizerChart.getData().add(gainSeries);
+ });
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/message/DroppedSamplesMessage.java b/src/main/java/io/github/dsheirer/message/DroppedSamplesMessage.java
new file mode 100644
index 00000000..d789c90d
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/message/DroppedSamplesMessage.java
@@ -0,0 +1,106 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2025 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.message;
+
+import io.github.dsheirer.identifier.Identifier;
+import io.github.dsheirer.protocol.Protocol;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Empty message to convey that a number of dropped samples produced a shortfall of expected bits. This can result
+ * from either the tuner dropping the samples, or from a decoder dropping samples due to timing adjustments.
+ *
+ * This message supports periodic updates to user to indicate that the USB bus and/or the tuner may be causing dropped
+ * samples.
+ */
+public class DroppedSamplesMessage extends Message
+{
+ private int mBitsDropped;
+ private Protocol mProtocol;
+ private int mTimeslot = 0;
+
+ /**
+ * Constructs a dropped samples message.
+ *
+ * @param timestamp of the message
+ * @param bitsDropped for the expected message length
+ * @param timeslot that lost the sync
+ */
+ public DroppedSamplesMessage(long timestamp, int bitsDropped, Protocol protocol, int timeslot)
+ {
+ super(timestamp);
+ mBitsDropped = bitsDropped;
+ mProtocol = protocol;
+ mTimeslot = timeslot;
+ }
+
+ /**
+ * Constructs a dropped samples message.
+ *
+ * @param timestamp of the message
+ * @param bitsDropped for the expected message length
+ */
+ public DroppedSamplesMessage(long timestamp, int bitsDropped, Protocol protocol)
+ {
+ this(timestamp, bitsDropped, protocol, 0);
+ }
+
+ /**
+ * Timeslot that has dropped bits
+ * @return timeslot or a default of 0
+ */
+ @Override
+ public int getTimeslot()
+ {
+ return mTimeslot;
+ }
+
+ /**
+ * Indicates the number of bits that were detected to be dropped
+ */
+ public int getBitsDropped()
+ {
+ return mBitsDropped;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "<-> DROPPED SAMPLES (POSSIBLY) DETECTED -- COULD NOT ACCOUNT FOR [" + getBitsDropped() + "] SYMBOL BITS";
+ }
+
+ @Override
+ public boolean isValid()
+ {
+ return true;
+ }
+
+ @Override
+ public Protocol getProtocol()
+ {
+ return mProtocol;
+ }
+
+ @Override
+ public List getIdentifiers()
+ {
+ return Collections.EMPTY_LIST;
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/module/ProcessingChain.java b/src/main/java/io/github/dsheirer/module/ProcessingChain.java
index f281545f..5c63c17b 100644
--- a/src/main/java/io/github/dsheirer/module/ProcessingChain.java
+++ b/src/main/java/io/github/dsheirer/module/ProcessingChain.java
@@ -177,9 +177,9 @@ public class ProcessingChain implements Listener
{
for(Module module : mModules)
{
- if(module instanceof PrimaryDecoder primaryDecoder)
+ if(module instanceof PrimaryDecoder decoder)
{
- return primaryDecoder;
+ return decoder;
}
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/FeedbackDecoder.java b/src/main/java/io/github/dsheirer/module/decode/FeedbackDecoder.java
index fb14cd06..7aa5c283 100644
--- a/src/main/java/io/github/dsheirer/module/decode/FeedbackDecoder.java
+++ b/src/main/java/io/github/dsheirer/module/decode/FeedbackDecoder.java
@@ -1,23 +1,20 @@
/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2025 Dennis Sheirer
*
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * 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
- * * *****************************************************************************
+ * 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;
@@ -30,9 +27,16 @@ import io.github.dsheirer.source.SourceEvent;
* Decoder that provides feedback to signal source(s) via SourceEvent broadcasts and supports registering source
* event listeners.
*/
-public abstract class FeedbackDecoder extends Decoder implements ISourceEventProvider
+public abstract class FeedbackDecoder extends PrimaryDecoder implements ISourceEventProvider
{
private Listener mSourceEventListener;
+ private Listener mSymbolListener;
+
+ /**
+ * Protocol description suitable for display in the user interface
+ * @return description
+ */
+ public abstract String getProtocolDescription();
/**
* Registers the listener to receive source events from this decoder
@@ -62,4 +66,43 @@ public abstract class FeedbackDecoder extends Decoder implements ISourceEventPro
mSourceEventListener.receive(sourceEvent);
}
}
+
+ /**
+ * Processes the current phase-locked loop (PLL) measurement and sends to the parent tuner for self correction.
+ * @param pllError as measured in the decoder.
+ */
+ public void processPLLError(float pllError, int baudRate)
+ {
+ long frequencyError = (long)(baudRate / 2.0 * (pllError / Math.PI));
+ broadcast(SourceEvent.frequencyErrorMeasurementSyncLocked(frequencyError, "Decoder measured error sync locked"));
+ }
+
+ /**
+ * Registers the listener to receive demodulated symbols.
+ * @param listener to receive symbols.
+ */
+ public void setSymbolListener(Listener listener)
+ {
+ mSymbolListener = listener;
+ }
+
+ /**
+ * Removes any registered symbol listener
+ */
+ public void removeSymbolListener()
+ {
+ mSymbolListener = null;
+ }
+
+ /**
+ * Broadcasts the demodulated symbol to a symbol listener.
+ * @param symbol in range 0 to +/- PI radians
+ */
+ public void broadcast(float symbol)
+ {
+ if(mSymbolListener != null)
+ {
+ mSymbolListener.receive(symbol);
+ }
+ }
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/PrimaryDecoder.java b/src/main/java/io/github/dsheirer/module/decode/PrimaryDecoder.java
index b6d9702d..3aad14ec 100644
--- a/src/main/java/io/github/dsheirer/module/decode/PrimaryDecoder.java
+++ b/src/main/java/io/github/dsheirer/module/decode/PrimaryDecoder.java
@@ -1,71 +1,27 @@
/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2025 Dennis Sheirer
*
- * * ******************************************************************************
- * * Copyright (C) 2014-2019 Dennis Sheirer
- * *
- * * This program is free software: you can redistribute it and/or modify
- * * it under the terms of the GNU General Public License as published by
- * * the Free Software Foundation, either version 3 of the License, or
- * * (at your option) any later version.
- * *
- * * 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
- * * *****************************************************************************
+ * 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;
-import io.github.dsheirer.audio.squelch.ISquelchStateProvider;
-import io.github.dsheirer.audio.squelch.SquelchStateEvent;
-import io.github.dsheirer.module.decode.config.DecodeConfiguration;
-import io.github.dsheirer.sample.Listener;
-
/**
- * Primary decoder adds the following functionality over the basic decoder:
- *
- * - Provides audio squelch control
+ * Base class for primary decoder
*/
-
-public abstract class PrimaryDecoder extends Decoder implements ISquelchStateProvider
+public abstract class PrimaryDecoder extends Decoder
{
- protected Listener mSquelchStateListener;
-
- protected DecodeConfiguration mDecodeConfiguration;
-
- public PrimaryDecoder(DecodeConfiguration config)
- {
- mDecodeConfiguration = config;
- }
-
- public DecodeConfiguration getDecodeConfiguration()
- {
- return mDecodeConfiguration;
- }
-
- public void broadcast(SquelchStateEvent state)
- {
- if(mSquelchStateListener != null)
- {
- mSquelchStateListener.receive(state);
- }
- }
-
- @Override
- public void setSquelchStateListener(Listener listener)
- {
- mSquelchStateListener = listener;
- }
-
- @Override
- public void removeSquelchStateListener()
- {
- mSquelchStateListener = null;
- }
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/SquelchControlDecoder.java b/src/main/java/io/github/dsheirer/module/decode/SquelchControlDecoder.java
new file mode 100644
index 00000000..8ae2bd6a
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/module/decode/SquelchControlDecoder.java
@@ -0,0 +1,71 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2025 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