mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
* P25 Phase 2 now supports control channel decoding and decoder was enhanced to improve decodes. * Radio reference site editor updated for phase 2 sites to allow user to select FDMA or TDMA control. * Decode events are now minimized and de-duplicated. * Fully parsing all phase 1/2 messages from the latest ICD. * Vendor specific messaging recoveries (Moto & Harris). * Patch group management enhancements with stale patch detection. * Tuner editor now fully resets the min/max frequency values * Default traffic channel count increased to 20 (from 3). * ISSI roaming radio and talkgroup values now displayed and aliasable as fully qualified values (e.g. 1234(123.456.7890) * Moto emergency alarm activation messaging support * Expanded list of P25 encryption algorithms * Message (bits) viewer enhanced for P25 phase 1 and phase 2 * IPV4 addresses and UDP ports no longer classified as user values - won't display in event views. * New framework for describing message binary fields that should reduce overall memory footprint and enhance code readability Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.gui.viewer;
|
||||
|
||||
import io.github.dsheirer.channel.state.DecoderStateEvent;
|
||||
import io.github.dsheirer.module.decode.event.DecodeEventSnapshot;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
/**
|
||||
* JavaFX message package details viewer
|
||||
*/
|
||||
public class MessagePackageViewer extends VBox
|
||||
{
|
||||
private Label mMessageLabel;
|
||||
private TableView<DecoderStateEvent> mDecoderStateEventTableView;
|
||||
private TableView<DecodeEventSnapshot> mDecodeEventTableView;
|
||||
private IdentifierCollectionViewer mIdentifierCollectionViewer;
|
||||
private ChannelStartProcessingRequestViewer mChannelStartProcessingRequestViewer;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
*/
|
||||
public MessagePackageViewer()
|
||||
{
|
||||
GridPane gridPane = new GridPane();
|
||||
gridPane.setHgap(5);
|
||||
gridPane.setVgap(5);
|
||||
Label messageLabel = new Label("Message:");
|
||||
gridPane.add(messageLabel, 0, 0);
|
||||
GridPane.setHgrow(getMessageLabel(), Priority.ALWAYS);
|
||||
gridPane.add(getMessageLabel(), 1, 0);
|
||||
|
||||
gridPane.add(new Label("Decoder State Events"), 0, 1);
|
||||
getDecoderStateEventTableView().setPrefHeight(120);
|
||||
GridPane.setHgrow(getDecoderStateEventTableView(), Priority.NEVER);
|
||||
gridPane.add(getDecoderStateEventTableView(), 0, 2);
|
||||
|
||||
gridPane.add(new Label("Decode Events"), 1, 1);
|
||||
getDecodeEventTableView().setPrefHeight(120);
|
||||
GridPane.setHgrow(getDecodeEventTableView(), Priority.ALWAYS);
|
||||
gridPane.add(getDecodeEventTableView(), 1, 2);
|
||||
|
||||
gridPane.add(new Label("Channel Start Processing Request"), 0, 3);
|
||||
gridPane.add(getChannelStartProcessingRequestViewer(), 0, 4);
|
||||
|
||||
getIdentifierCollectionViewer().setPrefHeight(120);
|
||||
gridPane.add(new Label("Selected Decode Event Identifiers"), 1, 3);
|
||||
gridPane.add(getIdentifierCollectionViewer(), 1, 4);
|
||||
|
||||
getChildren().add(gridPane);
|
||||
}
|
||||
|
||||
public void set(MessagePackage messagePackage)
|
||||
{
|
||||
getMessageLabel().setText(null);
|
||||
getDecoderStateEventTableView().getItems().clear();
|
||||
getDecodeEventTableView().getItems().clear();
|
||||
getChannelStartProcessingRequestViewer().set(null);
|
||||
|
||||
if(messagePackage != null)
|
||||
{
|
||||
String message = messagePackage.toString();
|
||||
if(message.length() > 40)
|
||||
{
|
||||
message = message.substring(0, 40) + "...";
|
||||
}
|
||||
getMessageLabel().setText(message);
|
||||
getDecoderStateEventTableView().getItems().addAll(messagePackage.getDecoderStateEvents());
|
||||
getDecodeEventTableView().getItems().addAll(messagePackage.getDecodeEvents());
|
||||
getChannelStartProcessingRequestViewer().set(messagePackage.getChannelStartProcessingRequest());
|
||||
|
||||
if(getDecodeEventTableView().getItems().size() > 0)
|
||||
{
|
||||
getDecodeEventTableView().getSelectionModel().select(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IdentifierCollectionViewer getIdentifierCollectionViewer()
|
||||
{
|
||||
if(mIdentifierCollectionViewer == null)
|
||||
{
|
||||
mIdentifierCollectionViewer = new IdentifierCollectionViewer();
|
||||
}
|
||||
|
||||
return mIdentifierCollectionViewer;
|
||||
}
|
||||
|
||||
private Label getMessageLabel()
|
||||
{
|
||||
if(mMessageLabel == null)
|
||||
{
|
||||
mMessageLabel = new Label();
|
||||
mMessageLabel.setMaxWidth(Double.MAX_VALUE);
|
||||
}
|
||||
|
||||
return mMessageLabel;
|
||||
}
|
||||
|
||||
public TableView<DecoderStateEvent> getDecoderStateEventTableView()
|
||||
{
|
||||
if(mDecoderStateEventTableView == null)
|
||||
{
|
||||
mDecoderStateEventTableView = new TableView<>();
|
||||
|
||||
TableColumn timeslotColumn = new TableColumn();
|
||||
timeslotColumn.setPrefWidth(110);
|
||||
timeslotColumn.setText("Timeslot");
|
||||
timeslotColumn.setCellValueFactory(new PropertyValueFactory<>("timeslot"));
|
||||
|
||||
TableColumn stateColumn = new TableColumn();
|
||||
stateColumn.setPrefWidth(110);
|
||||
stateColumn.setText("State");
|
||||
stateColumn.setCellValueFactory(new PropertyValueFactory<>("state"));
|
||||
|
||||
TableColumn eventColumn = new TableColumn();
|
||||
eventColumn.setPrefWidth(110);
|
||||
eventColumn.setText("Event");
|
||||
eventColumn.setCellValueFactory(new PropertyValueFactory<>("event"));
|
||||
|
||||
TableColumn frequencyColumn = new TableColumn();
|
||||
frequencyColumn.setPrefWidth(110);
|
||||
frequencyColumn.setText("Frequency");
|
||||
frequencyColumn.setCellValueFactory(new PropertyValueFactory<>("frequency"));
|
||||
|
||||
mDecoderStateEventTableView.getColumns().addAll(timeslotColumn, stateColumn, eventColumn, frequencyColumn);
|
||||
}
|
||||
|
||||
return mDecoderStateEventTableView;
|
||||
}
|
||||
|
||||
private TableView<DecodeEventSnapshot> getDecodeEventTableView()
|
||||
{
|
||||
if(mDecodeEventTableView == null)
|
||||
{
|
||||
mDecodeEventTableView = new TableView<>();
|
||||
mDecodeEventTableView.setMaxWidth(Double.MAX_VALUE);
|
||||
|
||||
TableColumn startTimeColumn = new TableColumn();
|
||||
startTimeColumn.setPrefWidth(110);
|
||||
startTimeColumn.setText("Start");
|
||||
startTimeColumn.setCellValueFactory(new PropertyValueFactory<>("timeStart"));
|
||||
|
||||
TableColumn durationColumn = new TableColumn();
|
||||
durationColumn.setPrefWidth(110);
|
||||
durationColumn.setText("Duration");
|
||||
durationColumn.setCellValueFactory(new PropertyValueFactory<>("duration"));
|
||||
|
||||
TableColumn typeColumn = new TableColumn();
|
||||
typeColumn.setPrefWidth(130);
|
||||
typeColumn.setText("Type");
|
||||
typeColumn.setCellValueFactory(new PropertyValueFactory<>("eventType"));
|
||||
|
||||
TableColumn channelDescriptorColumn = new TableColumn();
|
||||
channelDescriptorColumn.setPrefWidth(110);
|
||||
channelDescriptorColumn.setText("Channel");
|
||||
channelDescriptorColumn.setCellValueFactory(new PropertyValueFactory<>("channelDescriptor"));
|
||||
|
||||
TableColumn frequencyColumn = new TableColumn();
|
||||
frequencyColumn.setPrefWidth(110);
|
||||
frequencyColumn.setText("Frequency");
|
||||
frequencyColumn.setCellValueFactory(new PropertyValueFactory<>("frequency"));
|
||||
|
||||
TableColumn hashcodeColumn = new TableColumn();
|
||||
hashcodeColumn.setPrefWidth(100);
|
||||
hashcodeColumn.setText("Hash ID");
|
||||
hashcodeColumn.setCellValueFactory(new PropertyValueFactory<>("originalHashCode"));
|
||||
|
||||
TableColumn detailsColumn = new TableColumn();
|
||||
detailsColumn.setPrefWidth(500);
|
||||
detailsColumn.setText("Details");
|
||||
detailsColumn.setCellValueFactory(new PropertyValueFactory<>("details"));
|
||||
|
||||
mDecodeEventTableView.getColumns().addAll(startTimeColumn, durationColumn, typeColumn, channelDescriptorColumn,
|
||||
frequencyColumn, hashcodeColumn, detailsColumn);
|
||||
|
||||
mDecodeEventTableView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) ->
|
||||
{
|
||||
if(newValue != null)
|
||||
{
|
||||
getIdentifierCollectionViewer().set(newValue.getIdentifierCollection());
|
||||
}
|
||||
else
|
||||
{
|
||||
getIdentifierCollectionViewer().set(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return mDecodeEventTableView;
|
||||
}
|
||||
|
||||
private ChannelStartProcessingRequestViewer getChannelStartProcessingRequestViewer()
|
||||
{
|
||||
if(mChannelStartProcessingRequestViewer == null)
|
||||
{
|
||||
mChannelStartProcessingRequestViewer = new ChannelStartProcessingRequestViewer();
|
||||
}
|
||||
|
||||
return mChannelStartProcessingRequestViewer;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user