[WIP] Cleanup. Refactors DecoderFX application to the gui package.

This commit is contained in:
Denny
2018-06-15 07:29:27 -04:00
parent f4793f3cfd
commit 7a830077bd
36 changed files with 58 additions and 58 deletions

View File

@@ -0,0 +1,234 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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.P25Decoder;
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;
/**
* 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 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, 1500, 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(P25Decoder.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<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Open an I/Q recording file");
File file = fileChooser.showOpenDialog(mStage);
getViewerDesktop().load(file);
getRecentFilesMenu().add(file);
}
});
MenuItem closeMenuItem = new MenuItem("Close");
closeMenuItem.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
getViewerDesktop().close();
}
});
MenuItem exitMenuItem = new MenuItem("Exit");
exitMenuItem.setOnAction(new EventHandler<ActionEvent>()
{
@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<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
getViewerDesktop().setP25Phase1Decoder(P25Decoder.Modulation.C4FM);
setTitle(decoderType);
}
});
decoderMenu.getItems().add(c4fmDecoderMenuItem);
MenuItem lsmDecoderMenuItem = new MenuItem("P25 Phase 1 LSM");
lsmDecoderMenuItem.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
getViewerDesktop().setP25Phase1Decoder(P25Decoder.Modulation.CQPSK);
setTitle(decoderType);
}
});
decoderMenu.getItems().add(lsmDecoderMenuItem);
}
else
{
MenuItem decoderMenuItem = new MenuItem(decoderType.getShortDisplayString());
decoderMenuItem.setOnAction(new EventHandler<ActionEvent>()
{
@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);
}
}

View File

@@ -0,0 +1,385 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.gui.instrument;
import io.github.dsheirer.gui.instrument.decoder.AbstractDecoderPane;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
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 org.kordamp.ikonli.fontawesome.FontAwesome;
import org.kordamp.ikonli.javafx.FontIcon;
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<ActionEvent> mPlayEventHandler;
private AbstractDecoderPane mSampleRateListener;
private IControllableFileSource mControllableFileSource;
private ReusableBufferBroadcaster mReusableBufferBroadcaster = new ReusableBufferBroadcaster();
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(mReusableBufferBroadcaster);
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(mReusableBufferBroadcaster);
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 complex buffers from this playback
*/
public void addListener(Listener<ReusableBuffer> listener)
{
mReusableBufferBroadcaster.addListener(listener);
}
/**
* Removes the listener from receiving complex buffers from this playback
*/
public void removeListener(Listener<ReusableBuffer> listener)
{
mReusableBufferBroadcaster.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);
getPlay100Button().setDisable(true);
getPlay1000Button().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);
getPlay100Button().setDisable(false);
getPlay1000Button().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();
mRewindButton.setGraphic(new FontIcon(FontAwesome.FAST_BACKWARD));
}
return mRewindButton;
}
private Button getPlay1Button()
{
if(mPlay1Button == null)
{
mPlay1Button = new Button("1");
mPlay1Button.setUserData(1);
mPlay1Button.setOnAction(getPlaybackEventHandler());
mPlay1Button.setGraphic(new FontIcon(FontAwesome.PLAY));
}
return mPlay1Button;
}
private Button getPlay10Button()
{
if(mPlay10Button == null)
{
mPlay10Button = new Button("10");
mPlay10Button.setUserData(10);
mPlay10Button.setOnAction(getPlaybackEventHandler());
mPlay10Button.setGraphic(new FontIcon(FontAwesome.FAST_FORWARD));
}
return mPlay10Button;
}
private Button getPlay30Button()
{
if(mPlay30Button == null)
{
mPlay30Button = new Button("30");
mPlay30Button.setUserData(30);
mPlay30Button.setOnAction(getPlaybackEventHandler());
mPlay30Button.setGraphic(new FontIcon(FontAwesome.FAST_FORWARD));
}
return mPlay30Button;
}
private Button getPlay100Button()
{
if(mPlay100Button == null)
{
mPlay100Button = new Button("100");
mPlay100Button.setUserData(100);
mPlay100Button.setOnAction(getPlaybackEventHandler());
mPlay100Button.setGraphic(new FontIcon(FontAwesome.FAST_FORWARD));
}
return mPlay100Button;
}
private Button getPlay1000Button()
{
if(mPlay1000Button == null)
{
mPlay1000Button = new Button("1000");
mPlay1000Button.setUserData(1000);
mPlay1000Button.setOnAction(getPlaybackEventHandler());
mPlay1000Button.setGraphic(new FontIcon(FontAwesome.FAST_FORWARD));
}
return mPlay1000Button;
}
private Button getPlay2000Button()
{
if(mPlay2000Button == null)
{
mPlay2000Button = new Button("2000");
mPlay2000Button.setUserData(2000);
mPlay2000Button.setOnAction(getPlaybackEventHandler());
mPlay2000Button.setGraphic(new FontIcon(FontAwesome.FAST_FORWARD));
}
return mPlay2000Button;
}
private EventHandler<ActionEvent> getPlaybackEventHandler()
{
if(mPlayEventHandler == null)
{
mPlayEventHandler = new EventHandler<ActionEvent>()
{
@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?");
}
}

View File

@@ -0,0 +1,207 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.gui.instrument;
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<ActionEvent>
{
private Preferences mPreferences = Preferences.userNodeForPackage(RecentFilesMenu.class);
private IFileSelectionListener mFileSelectionListener;
private String mIdentifier;
private int mSize;
/**
* Recently used files menu. Uses java Preferences to store recently accessed files and provides access to those
* files via child menu items to this menu.
*
* @param label to use for this menu.
* @param uniqueIdentifier to use in addition to the class path of this class to uniquely identify recently accessed
* files in a java Preferences data store.
* @param size of the maximum number of recent files to present to the user
*/
public RecentFilesMenu(String label, String uniqueIdentifier, int size)
{
super(label);
mIdentifier = uniqueIdentifier;
mSize = size;
load();
}
/**
* Registers the listener to receive file selection events when the user selects a recently used file.
* @param listener to receive file selection events
*/
public void setFileSelectionListener(IFileSelectionListener listener)
{
mFileSelectionListener = listener;
}
/**
* Adds the file to the recently accessed files list. If this file is already included in the recently files list,
* it will be promoted to the first menu item and all other recently used files will be demoted.
*
* @param file to add to the recently used files list.
*/
public void add(File file)
{
if(file != null)
{
String filePath = file.getAbsolutePath();
int index = mSize - 1;
//Check to see if this file is already in the recent files list
for(int x = mSize - 1; x >= 0; x--)
{
String existingItem = mPreferences.get(getKey(x), null);
if(existingItem != null && existingItem.equals(filePath))
{
index = x;
break;
}
}
//Shift all recent files down to make room for the newly added file at the top of the list
while(index > 0)
{
String newerItem = mPreferences.get(getKey(index - 1), null);
if(newerItem != null)
{
mPreferences.put(getKey(index), newerItem);
}
index--;
}
mPreferences.put(getKey(0), file.getAbsolutePath());
}
load();
}
/**
* Creates a unique key value for each numbered recently used file item in the preferences.
*
* @param index of recent file item.
* @return unique key to use with the preferences instance.
*/
private String getKey(int index)
{
return mIdentifier + ".recent.file." + index;
}
/**
* Clears and (re)loads all child recent file menu items.
*/
private void load()
{
getItems().clear();
for(int x = 0; x < mSize; x++)
{
String path = mPreferences.get(getKey(x), null);
if(path != null)
{
File file = new File(path);
if(file.isFile())
{
MenuItem menuItem = new MenuItem(file.getName());
menuItem.setUserData(file);
menuItem.setOnAction(this);
getItems().add(menuItem);
}
}
}
if(getItems().size() > 0)
{
setDisable(false);
getItems().add(new SeparatorMenuItem());
MenuItem clearMenuItem = new MenuItem("Clear History");
clearMenuItem.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
clearHistory();
}
});
getItems().add(clearMenuItem);
}
else
{
setDisable(true);
}
}
/**
* Clears the recently used files history and removes all items from the preferences instance
*/
private void clearHistory()
{
for(int x = 0; x < mSize; x++)
{
mPreferences.remove(getKey(x));
}
load();
}
/**
* Event handler for all recent file child menu items. Extracts the selected file stored as the user data object
* in each of the menu items and notifies the listener that the recent file has been selected.
*
* @param event from a recent file menu item child of this menu.
*/
@Override
public void handle(ActionEvent event)
{
if(mFileSelectionListener != null)
{
if(event.getSource() instanceof MenuItem)
{
Object fileObject = ((MenuItem)event.getSource()).getUserData();
if(fileObject instanceof File)
{
mFileSelectionListener.fileSelected((File)fileObject);
}
}
}
}
/**
* Listener interface for file selection events.
*/
public interface IFileSelectionListener
{
void fileSelected(File file);
}
}

View File

@@ -0,0 +1,90 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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.module.decode.DecoderType;
import io.github.dsheirer.module.decode.p25.P25Decoder;
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(P25Decoder.Modulation modulation)
{
setDecoderPane(DecoderPaneFactory.getP25DecoderPane(modulation));
}
private void setDecoderPane(AbstractDecoderPane decoderPane)
{
getPlaybackController().removeListener(getDecoderPane());
getChildren().remove(getDecoderPane());
mDecoderPane = decoderPane;
setCenter(getDecoderPane());
getPlaybackController().addListener(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;
}
}

View File

@@ -0,0 +1,169 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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<Data<Integer,Float>> mSamples = FXCollections.observableArrayList();
private Series<Integer,Float> mSampleSeries = new Series<>("Samples", mSamples);
private ObservableList<Data<Number,Number>> mSamplePoints = FXCollections.observableArrayList();
private Series<Number,Number> mSamplePointSeries = new Series<>("Pointers", mSamplePoints);
private ObservableList<Data<Number,Number>> mSymbolSamples = FXCollections.observableArrayList();
private Series<Number,Number> mSymbolSamplesSeries = new Series<>("Next Symbol Samples", mSymbolSamples);
private ObservableList<Data<Number,Number>> mPreviousSymbol = FXCollections.observableArrayList();
private Series<Number,Number> mPreviousSymbolSeries = new Series<>("Previous Symbol", mPreviousSymbol);
private ObservableList<Data<Number,Number>> mZeroCrossing = FXCollections.observableArrayList();
private Series<Number,Number> 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<Series> 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<Integer,Float> 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<Integer,Float> 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<Number,Number> sample = new Data<>(0.0, -0.55);
mPreviousSymbol.add(sample);
}
while(mZeroCrossing.size() < 2)
{
Data<Number,Number> sample = new Data<>(0.0, -0.65);
mZeroCrossing.add(sample);
}
while(mSamplePoints.size() < 2)
{
Data<Number,Number> sample = new Data<>(0.0, -0.75);
mSamplePoints.add(sample);
}
while(mSymbolSamples.size() < 2)
{
Data<Number,Number> 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<Number,Number> 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);
}
}
}

View File

@@ -0,0 +1,118 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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<Data<Number,Number>> mCurrentSamples = FXCollections.observableArrayList();
private Series<Number,Number> mCurrentSampleSeries = new Series<>("Samples", mCurrentSamples);
private ObservableList<Data<Number,Number>> mPreviousSamples = FXCollections.observableArrayList();
private Series<Number,Number> mPreviousSampleSeries = new Series<>("Samples", mPreviousSamples);
private ObservableList<Data<Number,Number>> mDetected = FXCollections.observableArrayList();
private Series<Number,Number> 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<Series> 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<Number,Number> sample = new Data<>(x, 0.0f);
mCurrentSamples.add(sample);
Data<Number,Number> sample2 = new Data<>(x, 0.0f);
mPreviousSamples.add(sample2);
}
Data<Number,Number> detected1 = new Data<>(5, -0.25f);
mDetected.add(detected1);
Data<Number,Number> 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<Number,Number> 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<Number,Number> sample = mPreviousSamples.get(x);
sample.setYValue(samples[x] ? -0.4f : -0.6f);
}
if(error == 0.0f)
{
Data<Number,Number> detected1 = mDetected.get(0);
detected1.setXValue(0.0f);
Data<Number,Number> detected2 = mDetected.get(1);
detected2.setXValue(0.0f);
}
else
{
Data<Number,Number> detected1 = mDetected.get(0);
detected1.setXValue(mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getErrorDetector().getDetectedZeroCrossing());
Data<Number,Number> detected2 = mDetected.get(1);
detected2.setXValue(mIInstrumentedAFSK1200Decoder.getAFSK1200Decoder().getErrorDetector().getDetectedZeroCrossing());
}
}
}
}

View File

@@ -0,0 +1,123 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.gui.instrument.chart;
import io.github.dsheirer.buffer.ComplexCircularBuffer;
import io.github.dsheirer.dsp.gain.ComplexGain;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.complex.Complex;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ComplexPhaseLineChart extends LineChart implements Listener<ReusableComplexBuffer>
{
private final static Logger mLog = LoggerFactory.getLogger(ComplexPhaseLineChart.class);
private static final Complex ANGLE_OFFSET_45_DEGREES = Complex.fromAngle(Math.PI / 4.0);
private ComplexCircularBuffer mComplexCircularBuffer;
private ComplexGain mComplexGain = new ComplexGain(600.0f);
private ObservableList<Data<Integer,Float>> mPhaseValues = FXCollections.observableArrayList();
private IntegerProperty mLengthProperty = new SimpleIntegerProperty(40);
public ComplexPhaseLineChart(int length)
{
super(new NumberAxis("Time", 1, length - 10, 2),
new NumberAxis("Phase", -Math.PI, Math.PI, Math.PI / 2.0));
Series<Integer,Float> phaseSeries = new Series<>("Phase", mPhaseValues);
ObservableList<Series<Integer,Float>> observableList = FXCollections.observableArrayList(phaseSeries);
setData(observableList);
init(length);
}
private void init(int length)
{
mLengthProperty.addListener(new ChangeListener<Number>()
{
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue)
{
mComplexCircularBuffer = new ComplexCircularBuffer(newValue.intValue());
}
});
mComplexCircularBuffer = new ComplexCircularBuffer(length);
length().setValue(length);
for(int x = 10; x <= length; x++)
{
mPhaseValues.add(new Data(x - 10, 0.0f));
}
}
/**
* Length of the x-axis for displaying samples
*/
public IntegerProperty length()
{
return mLengthProperty;
}
@Override
public void receive(ReusableComplexBuffer complexBuffer)
{
float[] samples = complexBuffer.getSamples();
Complex sample;
for(int x = 0; x < samples.length; x += 2)
{
sample = new Complex(samples[x], samples[x + 1]);
Complex copy = sample.copy();
mComplexGain.apply(copy);
mComplexCircularBuffer.put(copy);
}
complexBuffer.decrementUserCount();
updateChart();
}
private void updateChart()
{
Complex[] samples = mComplexCircularBuffer.getAll();
for(int x = 10; x < samples.length; x++)
{
Complex previous = samples[x - 10].copy();
Complex sample = samples[x].copy();
if(previous != null && sample != null)
{
// previous.normalize();
// sample.normalize();
previous.add(ANGLE_OFFSET_45_DEGREES);
sample.multiply(previous.conjugate());
// sample.normalize();
mPhaseValues.get(x - 9).setYValue(sample.angle());
}
}
}
}

View File

@@ -0,0 +1,133 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.gui.instrument.chart;
import io.github.dsheirer.buffer.ComplexCircularBuffer;
import io.github.dsheirer.dsp.gain.ComplexGain;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.sample.complex.Complex;
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<ReusableComplexBuffer>
{
private final static Logger mLog = LoggerFactory.getLogger(ComplexSampleLineChart.class);
private ComplexCircularBuffer mComplexCircularBuffer;
private ComplexCircularBuffer mDemodulationCircularBuffer;
private ComplexGain mComplexGain = new ComplexGain(500.0f);
private ObservableList<XYChart.Data<Integer,Float>> mISamples = FXCollections.observableArrayList();
private ObservableList<XYChart.Data<Integer,Float>> mQSamples = FXCollections.observableArrayList();
private IntegerProperty mLengthProperty = new SimpleIntegerProperty(40);
public ComplexSampleLineChart(int length, int samplesPerSymbol)
{
super(new NumberAxis("Differential-Demodulated Samples", 0, length, 10),
new NumberAxis("Value", -1.0, 1.0, 0.25));
LineChart.Series<Integer,Float> iSampleSeries = new LineChart.Series<>("Inphase", mISamples);
LineChart.Series<Integer,Float> qSampleSeries = new LineChart.Series<>("Quadrature", mQSamples);
ObservableList<XYChart.Series<Integer,Float>> 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<Number>()
{
@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(ReusableComplexBuffer complexBuffer)
{
float[] samples = complexBuffer.getSamples();
Complex sample = new Complex(0,0);
for(int x = 0; x < samples.length; x += 2)
{
sample.setValues(samples[x], samples[x + 1]);
// mComplexGain.apply(sample);
sample.normalize();
Complex previous = mDemodulationCircularBuffer.get(sample.copy());
sample.multiply(previous.conjugate());
mComplexCircularBuffer.put(sample.copy());
}
updateChart();
complexBuffer.decrementUserCount();
}
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());
}
}
}
}

View File

@@ -0,0 +1,73 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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<Boolean>
{
private final static Logger mLog = LoggerFactory.getLogger(DecodedSymbolChart.class);
private ObservableList<Data<Number,Number>> mSymbols = FXCollections.observableArrayList();
private Series<Number,Number> 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<Series> observableList = FXCollections.observableArrayList(mSymbolSeries);
setData(observableList);
for(int x = 0; x < length; x++)
{
Data<Number,Number> 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<Number,Number> symbol = mSymbols.get(x);
int offset = x + mSymbolBufferPointer;
offset %= mSymbolBuffer.length;
symbol.setYValue(mSymbolBuffer[offset] ? 0.5f : -0.5f);
}
}
}

View File

@@ -0,0 +1,72 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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 DoubleLineChart extends LineChart implements Listener<Double>
{
private final static Logger mLog = LoggerFactory.getLogger(DoubleLineChart.class);
private DoubleCircularBuffer mDoubleCircularBuffer;
private ObservableList<Data<Integer,Double>> 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<Integer,Double> phaseSeries = new Series<>(seriesLabel, mPhaseValues);
ObservableList<Series<Integer,Double>> 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]);
}
}
}

View File

@@ -0,0 +1,121 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EyeDiagramChart extends LineChart implements Listener<SymbolDecisionData>
{
private final static Logger mLog = LoggerFactory.getLogger(EyeDiagramChart.class);
private ObservableList<Series<Double,Double>> mData = FXCollections.observableArrayList();
private int mSeriesCount;
private int mSeriesPointer;
private int mSeriesLength;
public EyeDiagramChart(int seriesCount, String legend)
{
super(new NumberAxis("Symbol Timing (" + legend + ")", 1.0, 10.0, 1.0),
new NumberAxis("Value", -1.25, 1.25, 0.25));
mSeriesCount = seriesCount * 2;
init();
}
private void init()
{
for(int x = 0; x < mSeriesCount; x++)
{
ObservableList<Data<Double,Double>> series = FXCollections.observableArrayList();
mData.add(new Series<>(series));
}
setData(mData);
}
private ObservableList<Data<Double,Double>> getSeries(int series, int length)
{
ObservableList<Data<Double,Double>> seriesData = mData.get(series).getData();
while(seriesData.size() > length)
{
seriesData.remove(0);
}
while(seriesData.size() < length)
{
seriesData.add(new Data<Double,Double>(0.0,0.0));
}
return seriesData;
}
private void checkChartLength(int length)
{
if(mSeriesLength != length)
{
((NumberAxis)getXAxis()).setUpperBound(length);
mSeriesLength = length;
}
}
@Override
public void receive(SymbolDecisionData symbolDecisionData)
{
Complex[] demodulated = symbolDecisionData.getDemodulated();
int length = demodulated.length;
checkChartLength(length);
ObservableList<Data<Double,Double>> iSeries = getSeries(mSeriesPointer++, length + 1);
if(mSeriesPointer >= mSeriesCount)
{
mSeriesPointer = 0;
}
ObservableList<Data<Double,Double>> qSeries = getSeries(mSeriesPointer++, length + 1);
if(mSeriesPointer >= mSeriesCount)
{
mSeriesPointer = 0;
}
for(int x = 0; x < length; x++)
{
demodulated[x].normalize();
Data<Double,Double> iDataPoint = iSeries.get(x);
iDataPoint.setXValue((double)x + 1 - symbolDecisionData.getSamplingPoint());
double iValue = demodulated[x].inphase();
iDataPoint.setYValue(iValue);
Data<Double,Double> qDataPoint = qSeries.get(x);
qDataPoint.setXValue((double)x + 1 - symbolDecisionData.getSamplingPoint());
double qValue = demodulated[x].quadrature();
qDataPoint.setYValue(qValue);
}
}
}

View File

@@ -0,0 +1,121 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.gui.instrument.chart;
import io.github.dsheirer.buffer.DoubleCircularBuffer;
import io.github.dsheirer.dsp.fm.FMDemodulator;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FMDemodulatedLineChart extends LineChart implements Listener<ReusableComplexBuffer>
{
private final static Logger mLog = LoggerFactory.getLogger(FMDemodulatedLineChart.class);
private DoubleCircularBuffer mDoubleCircularBuffer;
private int mSamplesPerSymbol;
private int mTwiceSamplesPerSymbol;
private int mSeriesCount;
private ObservableList<Series<Integer,Double>> mData = FXCollections.observableArrayList();
private Complex mPreviousSample = new Complex(0,0);
private int mSeriesPointer;
private int mSamplePointer;
public FMDemodulatedLineChart(int samplesPerSymbol, int seriesCount)
{
super(new NumberAxis("Time", 1, samplesPerSymbol * 2, 2),
new NumberAxis("Demodulated", -1.0, 1.0, 0.25));
mSamplesPerSymbol = samplesPerSymbol;
mTwiceSamplesPerSymbol = mSamplesPerSymbol * 2;
mSeriesCount = seriesCount;
init();
}
private void init()
{
int seriesLength = 2 * mSamplesPerSymbol;
mDoubleCircularBuffer = new DoubleCircularBuffer(seriesLength * mSeriesCount);
for(int x = 0; x < mSeriesCount; x++)
{
ObservableList<Data<Integer,Double>> series = FXCollections.observableArrayList();
for(int y = 0; y < seriesLength; y++)
{
series.add(new Data<Integer,Double>(y + 1, 0.0));
}
mData.add(new Series<>(series));
}
setData(mData);
}
@Override
public void receive(ReusableComplexBuffer complexBuffer)
{
float[] samples = complexBuffer.getSamples();
Complex sample;
for(int x = 0; x < samples.length; x += 2)
{
sample = new Complex(samples[x], samples[x + 1]);
double demodulated = FMDemodulator.demodulate(mPreviousSample, sample);
demodulated *= 2.0;
if(demodulated > 1.0)
{
demodulated = 1.0;
}
else if(demodulated < -1.0)
{
demodulated = -1.0;
}
mDoubleCircularBuffer.put(demodulated);
mPreviousSample = sample;
updateChart(demodulated);
}
complexBuffer.decrementUserCount();
}
private void updateChart(double value)
{
Series<Integer,Double> series = mData.get(mSeriesPointer);
Data data = series.getData().get(mSamplePointer++);
data.setYValue(value);
if(mSamplePointer >= mTwiceSamplesPerSymbol)
{
mSamplePointer = 0;
mSeriesPointer++;
if(mSeriesPointer >= mSeriesCount)
{
mSeriesPointer = 0;
}
}
}
}

View File

@@ -0,0 +1,30 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.gui.instrument.chart;
import io.github.dsheirer.dsp.afsk.AFSK1200DecoderInstrumented;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.sample.Listener;
import javafx.beans.property.SimpleIntegerProperty;
public interface IInstrumentedAFSK1200Decoder
{
public SimpleIntegerProperty getBufferCountProperty();
public AFSK1200DecoderInstrumented getAFSK1200Decoder();
public void setMessageListener(Listener<Message> listener);
}

View File

@@ -0,0 +1,171 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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<Data<Integer,Float>> mSamples = FXCollections.observableArrayList();
private Series<Integer,Float> mSampleSeries = new Series<>("Samples", mSamples);
private ObservableList<Data<Number,Number>> mSamplePoints = FXCollections.observableArrayList();
private Series<Number,Number> mSamplePointSeries = new Series<>("Pointers", mSamplePoints);
private ObservableList<Data<Number,Number>> mSymbolSamples = FXCollections.observableArrayList();
private Series<Number,Number> mSymbolSamplesSeries = new Series<>("Next Symbol Samples", mSymbolSamples);
private ObservableList<Data<Number,Number>> mSymbol = FXCollections.observableArrayList();
private Series<Number,Number> mSymbolSeries = new Series<>("Previous Symbol", mSymbol);
private ObservableList<Data<Number,Number>> mZeroCrossing = FXCollections.observableArrayList();
private Series<Number,Number> 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<Series> 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<Integer,Float> 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<Integer,Float> 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<Number,Number> sample = new Data<>(0.0, -0.55);
mSymbol.add(sample);
}
while(mZeroCrossing.size() < 2)
{
Data<Number,Number> sample = new Data<>(0.0, -0.65);
mZeroCrossing.add(sample);
}
while(mSamplePoints.size() < 2)
{
Data<Number,Number> sample = new Data<>(0.0, -0.75);
mSamplePoints.add(sample);
}
while(mSymbolSamples.size() < 2)
{
Data<Number,Number> 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<Number,Number> 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);
}
}
}

View File

@@ -0,0 +1,73 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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<Double>
{
private final static Logger mLog = LoggerFactory.getLogger(PhaseLineChart.class);
private DoubleCircularBuffer mDoubleCircularBuffer;
private ObservableList<Data<Integer,Double>> mPhaseValues = FXCollections.observableArrayList();
public PhaseLineChart(int length)
{
super(new NumberAxis("Time", 1, length, 2),
new NumberAxis("Phase", -0.8, 0.8, 0.1));
Series<Integer,Double> phaseSeries = new Series<>("PLL Phase Error", mPhaseValues);
ObservableList<Series<Integer,Double>> 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]);
}
}
}

View File

@@ -0,0 +1,85 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.gui.instrument.chart;
import io.github.dsheirer.buffer.RealCircularBuffer;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
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<ReusableBuffer>
{
private final static Logger mLog = LoggerFactory.getLogger(RealSampleLineChart.class);
private ObservableList<Data<Integer,Float>> mSamples = FXCollections.observableArrayList();
private Series<Integer,Float> mSampleSeries = new Series<>("Samples", mSamples);
private RealCircularBuffer mRealCircularBuffer;
public RealSampleLineChart(int length, double tickUnit)
{
super(new NumberAxis("Samples", 0, length, tickUnit),
new NumberAxis("Value", -1.0, 1.0, 0.25));
ObservableList<Series<Integer,Float>> observableList = FXCollections.observableArrayList(mSampleSeries);
setData(observableList);
init(length);
}
private void init(int length)
{
mRealCircularBuffer = new RealCircularBuffer(length);
for(int x = 0; x < length; x++)
{
Data<Integer,Float> 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(ReusableBuffer buffer)
{
for(float sample: buffer.getSamples())
{
mRealCircularBuffer.put(sample);
}
float[] bufferSamples = mRealCircularBuffer.get();
for(int x = 0; x < bufferSamples.length; x++)
{
Data<Integer,Float> sample = mSamples.get(x);
sample.setYValue(bufferSamples[x]);
}
buffer.decrementUserCount();
}
}

View File

@@ -0,0 +1,90 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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<Complex>
{
private final static Logger mLog = LoggerFactory.getLogger(SymbolChart.class);
private ObservableList<ScatterChart.Data> mCurrentPoints = FXCollections.observableArrayList();
// private ObservableList<ScatterChart.Data> mPreviousPoints = FXCollections.observableArrayList();
// private ObservableList<ScatterChart.Data> 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<XYChart.Series> 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;
}
}
}

View File

@@ -0,0 +1,132 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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<Data<Number,Number>> mCurrentSamples = FXCollections.observableArrayList();
private Series<Number,Number> mCurrentSampleSeries = new Series<>("Samples", mCurrentSamples);
private ObservableList<Data<Number,Number>> mPreviousSamples = FXCollections.observableArrayList();
private Series<Number,Number> mPreviousSampleSeries = new Series<>("Samples", mPreviousSamples);
private ObservableList<Data<Number,Number>> mIdeal = FXCollections.observableArrayList();
private Series<Number,Number> mIdealSeries = new Series<>("Ideal", mIdeal);
private ObservableList<Data<Number,Number>> mDetected = FXCollections.observableArrayList();
private Series<Number,Number> 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<Series> 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<Number,Number> sample = new Data<>(x, 0.0f);
mCurrentSamples.add(sample);
Data<Number,Number> sample2 = new Data<>(x, 0.0f);
mPreviousSamples.add(sample2);
}
Data<Number,Number> ideal1 = new Data<>(5, -0.1f);
mIdeal.add(ideal1);
Data<Number,Number> ideal2 = new Data<>(5, -0.9f);
mIdeal.add(ideal2);
Data<Number,Number> detected1 = new Data<>(5, -0.25f);
mDetected.add(detected1);
Data<Number,Number> 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<Number,Number> 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<Number,Number> sample = mPreviousSamples.get(x);
sample.setYValue(samples[x] ? -0.4f : -0.6f);
}
Data<Number,Number> ideal1 = mIdeal.get(0);
ideal1.setXValue(mLTRNetDecoderInstrumented.getLTRDecoder().getErrorDetector().getZeroCrossingIdeal());
Data<Number,Number> ideal2 = mIdeal.get(1);
ideal2.setXValue(mLTRNetDecoderInstrumented.getLTRDecoder().getErrorDetector().getZeroCrossingIdeal());
if(error == 0.0f)
{
Data<Number,Number> detected1 = mDetected.get(0);
detected1.setXValue(0.0f);
Data<Number,Number> detected2 = mDetected.get(1);
detected2.setXValue(0.0f);
}
else
{
Data<Number,Number> detected1 = mDetected.get(0);
detected1.setXValue(mLTRNetDecoderInstrumented.getLTRDecoder().getErrorDetector().getDetectedZeroCrossing());
Data<Number,Number> detected2 = mDetected.get(1);
detected2.setXValue(mLTRNetDecoderInstrumented.getLTRDecoder().getErrorDetector().getDetectedZeroCrossing());
}
}
}
}

View File

@@ -0,0 +1,162 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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.Message;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
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<ReusableBuffer>)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<Message>()
{
@Override
public void receive(Message message)
{
mLog.debug((message.isValid() ? "PASS " : "FAIL ") + message.getMessage());
}
});
}
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;
}
}

View File

@@ -0,0 +1,30 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.gui.instrument.decoder;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.SampleType;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import javafx.scene.layout.VBox;
public abstract class AbstractDecoderPane<T extends ReusableBuffer> extends VBox implements Listener<T>
{
abstract SampleType getSampleType();
public void setSampleRate(double sampleRate)
{
}
}

View File

@@ -0,0 +1,64 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.gui.instrument.decoder;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.SampleType;
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import javafx.scene.text.Text;
public class ComplexDecoderPane extends AbstractDecoderPane<ReusableComplexBuffer>
{
private ReusableBufferBroadcaster mComplexBufferBroadcaster = new ReusableBufferBroadcaster();
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(ReusableComplexBuffer reusableComplexBuffer)
{
mComplexBufferBroadcaster.broadcast(reusableComplexBuffer);
}
public void addListener(Listener<ReusableComplexBuffer> listener)
{
mComplexBufferBroadcaster.addListener(listener);
}
public void removeListener(Listener<ReusableComplexBuffer> listener)
{
mComplexBufferBroadcaster.removeListener(listener);
}
}

View File

@@ -0,0 +1,91 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.gui.instrument.decoder;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.p25.P25Decoder;
import java.util.EnumSet;
public class DecoderPaneFactory
{
private static final EnumSet<DecoderType> SUPPORTED_DECODER_TYPES = EnumSet.of(
DecoderType.P25_PHASE1,
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 getP25DecoderPane() method for P25 decoder type");
}
return getDefaultPane();
}
/**
* Creates a decoder pane for the P25 decoder type
*/
public static AbstractDecoderPane getP25DecoderPane(P25Decoder.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);
}
}

View File

@@ -0,0 +1,43 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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;
}
}

View File

@@ -0,0 +1,60 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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()
{
mLog.debug("Tower Sync Detected!");
}
});
mDecoder.getTransponderMessageFramer().setSyncDetectListener(new ISyncDetectListener()
{
@Override
public void syncDetected()
{
mLog.debug("Transponder Sync Detected!");
}
});
}
return mDecoder;
}
}

View File

@@ -0,0 +1,151 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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.Message;
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, null);
mDecoder.setMessageListener(new Listener<Message>()
{
@Override
public void receive(Message message)
{
mLog.debug(message.getMessage());
}
});
}
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;
}
}

View File

@@ -0,0 +1,52 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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()
{
mLog.debug("Sync Detected!");
}
});
}
return mDecoder;
}
}

View File

@@ -0,0 +1,60 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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()
{
// mLog.debug("Control Sync Detected!");
}
});
mDecoder.getTrafficMessageFramer().setSyncDetectListener(new ISyncDetectListener()
{
@Override
public void syncDetected()
{
// mLog.debug("Traffic Sync Detected!");
}
});
}
return mDecoder;
}
}

View File

@@ -0,0 +1,194 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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.Message;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.p25.P25DecoderC4FMInstrumented;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 ReusableBufferBroadcaster mFilteredBufferBroadcaster = new ReusableBufferBroadcaster();
private P25DecoderC4FMInstrumented mDecoder = new P25DecoderC4FMInstrumented(null);
public P25Phase1C4FMPane()
{
super(DecoderType.P25_PHASE1);
init();
}
private void init()
{
addListener(getDecoder());
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<Message>()
{
@Override
public void receive(Message message)
{
mLog.debug(message.getMessage());
}
});
}
@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 P25DecoderC4FMInstrumented 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(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;
}
}

View File

@@ -0,0 +1,194 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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.Message;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.p25.P25DecoderLSMInstrumented;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class P25Phase1LSMPane extends ComplexDecoderPane
{
private final static Logger mLog = LoggerFactory.getLogger(P25Phase1LSMPane.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 ReusableBufferBroadcaster mFilteredBufferBroadcaster = new ReusableBufferBroadcaster();
private P25DecoderLSMInstrumented mDecoder = new P25DecoderLSMInstrumented(null);
public P25Phase1LSMPane()
{
super(DecoderType.P25_PHASE1);
init();
}
private void init()
{
addListener(getDecoder());
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<Message>()
{
@Override
public void receive(Message message)
{
mLog.debug(message.getMessage());
}
});
}
@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 P25DecoderLSMInstrumented 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(100, 10);
}
return mSampleLineChart;
}
private EyeDiagramChart getEyeDiagramChart()
{
if(mEyeDiagramChart == null)
{
mEyeDiagramChart = new EyeDiagramChart(10, "Middle: 3-4 / Symbol: 8-9");
}
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;
}
}

View File

@@ -0,0 +1,68 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.gui.instrument.decoder;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.SampleType;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
import javafx.scene.text.Text;
public class RealDecoderPane extends AbstractDecoderPane<ReusableBuffer>
{
private ReusableBufferBroadcaster mBufferBroadcaster = new ReusableBufferBroadcaster();
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(ReusableBuffer reusableBuffer)
{
mBufferBroadcaster.broadcast(reusableBuffer);
}
public void addListener(Listener<ReusableBuffer> listener)
{
mBufferBroadcaster.addListener(listener);
}
public void removeListener(Listener<ReusableBuffer> listener)
{
mBufferBroadcaster.removeListener(listener);
}
public void setSampleRate(double sampleRate)
{
}
}

View File

@@ -0,0 +1,60 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
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()
{
mLog.debug("ANI Sync Detected!");
}
});
mDecoder.getGPSMessageFramer().setSyncDetectListener(new ISyncDetectListener()
{
@Override
public void syncDetected()
{
mLog.debug("GPS Sync Detected!");
}
});
}
return mDecoder;
}
}