mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
[WIP] Cleanup. Refactors DecoderFX application to the gui package.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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?");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user