#5 Playlist Editor With Radio Reference Support (#760)

* WIP - Adds support for aliasing P25 Phase 2 tones.Playlist editor - adds editor support for alias actions

* Playlist editor implementation and integration into application is complete. Adds JavaFX window monitoring to persist window size/location across application runs.

Co-authored-by: Denny <denny@denny-desktop>
This commit is contained in:
Denny Sheirer
2020-04-26 11:53:43 +00:00
committed by GitHub
parent 39f6d6c831
commit cc52ae5bd7
290 changed files with 31251 additions and 15306 deletions

View File

@@ -1,150 +0,0 @@
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
*
*/
package io.github.dsheirer.module.decode;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import javax.swing.JCheckBox;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
public class AuxDecodeConfigurationEditor extends Editor<Channel>
{
private static final long serialVersionUID = 1L;
private List<AuxDecoderCheckBox> mControls = new ArrayList<>();
public AuxDecodeConfigurationEditor()
{
init();
}
public AuxDecodeConfiguration getConfiguration()
{
return hasItem() ? getItem().getAuxDecodeConfiguration() : null;
}
private void init()
{
setLayout(new MigLayout("fill,wrap 4", "", "[][grow]"));
for(DecoderType decoder : DecoderType.AUX_DECODERS)
{
AuxDecoderCheckBox control = new AuxDecoderCheckBox(decoder);
control.setEnabled(false);
control.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(control);
mControls.add(control);
}
}
@Override
public void save()
{
if(hasItem())
{
AuxDecodeConfiguration config = getItem().getAuxDecodeConfiguration();
config.clearAuxDecoders();
for(AuxDecoderCheckBox checkBox : mControls)
{
if(checkBox.isSelected())
{
config.addAuxDecoder(checkBox.getDecoderType());
}
}
}
setModified(false);
}
private void setControlsEnabled(boolean enabled)
{
for(AuxDecoderCheckBox box : mControls)
{
if(box.isEnabled() != enabled)
{
box.setEnabled(enabled);
}
}
}
public class AuxDecoderCheckBox extends JCheckBox
{
private static final long serialVersionUID = 1L;
private DecoderType mDecoderType;
public AuxDecoderCheckBox(DecoderType decoder)
{
super(decoder.getDisplayString());
mDecoderType = decoder;
}
public DecoderType getDecoderType()
{
return mDecoderType;
}
}
@Override
public void setItem(Channel channel)
{
super.setItem(channel);
if(hasItem())
{
setControlsEnabled(true);
for(AuxDecoderCheckBox cb : mControls)
{
if(getItem().getAuxDecodeConfiguration().getAuxDecoders().contains(cb.getDecoderType()))
{
cb.setSelected(true);
}
else
{
cb.setSelected(false);
}
}
}
else
{
setControlsEnabled(false);
}
}
}

View File

@@ -1,139 +0,0 @@
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
*
*/
package io.github.dsheirer.module.decode;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.controller.channel.map.ChannelMapModel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EditorValidationException;
import io.github.dsheirer.gui.editor.EmptyValidatingEditor;
import io.github.dsheirer.gui.editor.ValidatingEditor;
import net.miginfocom.swing.MigLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class DecodeConfigurationEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
private JComboBox<DecoderType> mComboDecoders;
private ValidatingEditor<Channel> mCurrentEditor = new EmptyValidatingEditor<>("a decoder");
private ChannelMapModel mChannelMapModel;
public DecodeConfigurationEditor(final ChannelMapModel channelMapModel)
{
mChannelMapModel = channelMapModel;
init();
}
private void init()
{
setLayout(new MigLayout("wrap 2", "[][grow,fill]", "[align top][grow,fill]"));
mComboDecoders = new JComboBox<DecoderType>();
mComboDecoders.setEnabled(false);
DefaultComboBoxModel<DecoderType> model = new DefaultComboBoxModel<DecoderType>();
for(DecoderType type : DecoderType.PRIMARY_DECODERS)
{
model.addElement(type);
}
mComboDecoders.setModel(model);
mComboDecoders.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
DecoderType selected = mComboDecoders.getItemAt(mComboDecoders.getSelectedIndex());
ValidatingEditor<Channel> editor = DecoderFactory.getEditor(selected, mChannelMapModel);
setEditor(editor);
}
});
add(mComboDecoders);
add(mCurrentEditor);
}
private void setEditor(ValidatingEditor<Channel> editor)
{
if(mCurrentEditor != editor)
{
//Set channel to null in current editor to force a save prompt as required
if(mCurrentEditor.isModified())
{
mCurrentEditor.setItem(null);
}
remove(mCurrentEditor);
mCurrentEditor = editor;
mCurrentEditor.setSaveRequestListener(this);
mCurrentEditor.setItem(getItem());
add(mCurrentEditor);
revalidate();
repaint();
}
}
@Override
public void save()
{
if(hasItem())
{
mCurrentEditor.save();
}
setModified(false);
}
@Override
public void setItem(Channel channel)
{
super.setItem(channel);
if(hasItem())
{
mComboDecoders.setEnabled(true);
mComboDecoders.setSelectedItem(channel.getDecodeConfiguration().getDecoderType());
mCurrentEditor.setItem(channel);
}
else
{
mComboDecoders.setEnabled(false);
}
setModified(false);
}
@Override
public void validate(Editor<Channel> editor) throws EditorValidationException
{
mCurrentEditor.validate(editor);
}
}

View File

@@ -31,13 +31,10 @@ import io.github.dsheirer.controller.channel.map.ChannelMapModel;
import io.github.dsheirer.filter.AllPassFilter;
import io.github.dsheirer.filter.FilterSet;
import io.github.dsheirer.filter.IFilter;
import io.github.dsheirer.gui.editor.EmptyValidatingEditor;
import io.github.dsheirer.gui.editor.ValidatingEditor;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.message.MessageDirection;
import io.github.dsheirer.module.Module;
import io.github.dsheirer.module.decode.am.AMDecoder;
import io.github.dsheirer.module.decode.am.AMDecoderEditor;
import io.github.dsheirer.module.decode.am.DecodeConfigAM;
import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
@@ -49,12 +46,10 @@ import io.github.dsheirer.module.decode.lj1200.LJ1200DecoderState;
import io.github.dsheirer.module.decode.lj1200.LJ1200MessageFilter;
import io.github.dsheirer.module.decode.ltrnet.DecodeConfigLTRNet;
import io.github.dsheirer.module.decode.ltrnet.LTRNetDecoder;
import io.github.dsheirer.module.decode.ltrnet.LTRNetDecoderEditor;
import io.github.dsheirer.module.decode.ltrnet.LTRNetDecoderState;
import io.github.dsheirer.module.decode.ltrnet.LTRNetMessageFilter;
import io.github.dsheirer.module.decode.ltrstandard.DecodeConfigLTRStandard;
import io.github.dsheirer.module.decode.ltrstandard.LTRStandardDecoder;
import io.github.dsheirer.module.decode.ltrstandard.LTRStandardDecoderEditor;
import io.github.dsheirer.module.decode.ltrstandard.LTRStandardDecoderState;
import io.github.dsheirer.module.decode.ltrstandard.LTRStandardMessageFilter;
import io.github.dsheirer.module.decode.mdc1200.MDCDecoder;
@@ -62,30 +57,25 @@ import io.github.dsheirer.module.decode.mdc1200.MDCDecoderState;
import io.github.dsheirer.module.decode.mdc1200.MDCMessageFilter;
import io.github.dsheirer.module.decode.mpt1327.DecodeConfigMPT1327;
import io.github.dsheirer.module.decode.mpt1327.MPT1327Decoder;
import io.github.dsheirer.module.decode.mpt1327.MPT1327DecoderEditor;
import io.github.dsheirer.module.decode.mpt1327.MPT1327DecoderState;
import io.github.dsheirer.module.decode.mpt1327.MPT1327MessageFilter;
import io.github.dsheirer.module.decode.mpt1327.MPT1327TrafficChannelManager;
import io.github.dsheirer.module.decode.mpt1327.Sync;
import io.github.dsheirer.module.decode.nbfm.DecodeConfigNBFM;
import io.github.dsheirer.module.decode.nbfm.NBFMDecoder;
import io.github.dsheirer.module.decode.nbfm.NBFMDecoderEditor;
import io.github.dsheirer.module.decode.p25.P25TrafficChannelManager;
import io.github.dsheirer.module.decode.p25.audio.P25P1AudioModule;
import io.github.dsheirer.module.decode.p25.audio.P25P2AudioModule;
import io.github.dsheirer.module.decode.p25.phase1.DecodeConfigP25Phase1;
import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderC4FM;
import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderEditor;
import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderLSM;
import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderState;
import io.github.dsheirer.module.decode.p25.phase1.message.filter.P25MessageFilterSet;
import io.github.dsheirer.module.decode.p25.phase2.DecodeConfigP25Phase2;
import io.github.dsheirer.module.decode.p25.phase2.P25P2DecoderEditor;
import io.github.dsheirer.module.decode.p25.phase2.P25P2DecoderHDQPSK;
import io.github.dsheirer.module.decode.p25.phase2.P25P2DecoderState;
import io.github.dsheirer.module.decode.passport.DecodeConfigPassport;
import io.github.dsheirer.module.decode.passport.PassportDecoder;
import io.github.dsheirer.module.decode.passport.PassportDecoderEditor;
import io.github.dsheirer.module.decode.passport.PassportDecoderState;
import io.github.dsheirer.module.decode.passport.PassportMessageFilter;
import io.github.dsheirer.module.decode.tait.Tait1200Decoder;
@@ -148,7 +138,7 @@ public class DecoderFactory
case NBFM:
processNBFM(channel, modules, aliasList, decodeConfig);
break;
case LTR_STANDARD:
case LTR:
processLTRStandard(channel, modules, aliasList, (DecodeConfigLTRStandard) decodeConfig);
break;
case LTR_NET:
@@ -408,7 +398,7 @@ public class DecoderFactory
case LTR_NET:
filters.add(new LTRNetMessageFilter());
break;
case LTR_STANDARD:
case LTR:
filters.add(new LTRStandardMessageFilter());
break;
case MDC1200:
@@ -445,7 +435,7 @@ public class DecoderFactory
return new DecodeConfigAM();
case LTR_NET:
return new DecodeConfigLTRNet();
case LTR_STANDARD:
case LTR:
return new DecodeConfigLTRStandard();
case MPT1327:
return new DecodeConfigMPT1327();
@@ -462,33 +452,6 @@ public class DecoderFactory
}
}
public static ValidatingEditor<Channel> getEditor(DecoderType type, ChannelMapModel model)
{
switch(type)
{
case AM:
return new AMDecoderEditor();
case LTR_NET:
return new LTRNetDecoderEditor();
case LTR_STANDARD:
return new LTRStandardDecoderEditor();
case MPT1327:
return new MPT1327DecoderEditor(model);
case NBFM:
return new NBFMDecoderEditor();
case P25_PHASE1:
return new P25P1DecoderEditor();
case P25_PHASE2:
return new P25P2DecoderEditor();
case PASSPORT:
return new PassportDecoderEditor();
default:
break;
}
return new EmptyValidatingEditor<Channel>("a decoder");
}
/**
* Creates a copy of the configuration
*/
@@ -499,13 +462,16 @@ public class DecoderFactory
switch(config.getDecoderType())
{
case AM:
return new DecodeConfigAM();
DecodeConfigAM copyAM = new DecodeConfigAM();
DecodeConfigAM origAM = (DecodeConfigAM)config;
copyAM.setRecordAudio(origAM.getRecordAudio());
return copyAM;
case LTR_NET:
DecodeConfigLTRNet originalLTRNet = (DecodeConfigLTRNet)config;
DecodeConfigLTRNet copyLTRNet = new DecodeConfigLTRNet();
copyLTRNet.setMessageDirection(originalLTRNet.getMessageDirection());
return copyLTRNet;
case LTR_STANDARD:
case LTR:
DecodeConfigLTRStandard originalLTRStandard = (DecodeConfigLTRStandard)config;
DecodeConfigLTRStandard copyLTRStandard = new DecodeConfigLTRStandard();
copyLTRStandard.setMessageDirection(originalLTRStandard.getMessageDirection());
@@ -519,7 +485,11 @@ public class DecoderFactory
copyMPT.setTrafficChannelPoolSize(originalMPT.getTrafficChannelPoolSize());
return copyMPT;
case NBFM:
return new DecodeConfigNBFM();
DecodeConfigNBFM origNBFM = (DecodeConfigNBFM)config;
DecodeConfigNBFM copyNBFM = new DecodeConfigNBFM();
copyNBFM.setRecordAudio(origNBFM.getRecordAudio());
copyNBFM.setBandwidth(origNBFM.getBandwidth());
return copyNBFM;
case P25_PHASE1:
DecodeConfigP25Phase1 originalP25 = (DecodeConfigP25Phase1)config;
DecodeConfigP25Phase1 copyP25 = new DecodeConfigP25Phase1();

View File

@@ -32,7 +32,7 @@ public enum DecoderType
{
//Primary Decoders
AM("AM", "AM", Protocol.UNKNOWN),
LTR_STANDARD("LTR-Standard", "LTR", Protocol.LTR_STANDARD),
LTR("LTR", "LTR", Protocol.LTR),
LTR_NET("LTR-Net", "LTR-Net", Protocol.LTR_NET),
MPT1327("MPT1327", "MPT1327", Protocol.MPT1327),
NBFM("NBFM", "NBFM", Protocol.UNKNOWN),
@@ -63,7 +63,7 @@ public enum DecoderType
public static EnumSet<DecoderType> PRIMARY_DECODERS =
EnumSet.of(DecoderType.AM,
DecoderType.LTR_NET,
DecoderType.LTR_STANDARD,
DecoderType.LTR,
DecoderType.MPT1327,
DecoderType.NBFM,
DecoderType.P25_PHASE1,

View File

@@ -1,98 +0,0 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.module.decode.am;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EditorValidationException;
import io.github.dsheirer.gui.editor.ValidatingEditor;
import net.miginfocom.swing.MigLayout;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class AMDecoderEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
private JCheckBox mCheckBoxRecordAudio;
public AMDecoderEditor()
{
setLayout(new MigLayout("insets 0 0 0 0", "", ""));
add(new JLabel("AM Decoder"));
mCheckBoxRecordAudio = new JCheckBox("Record Audio");
mCheckBoxRecordAudio.setEnabled(false);
mCheckBoxRecordAudio.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mCheckBoxRecordAudio);
}
@Override
public void validate(Editor<Channel> editor) throws EditorValidationException
{
}
@Override
public void setItem(Channel item)
{
super.setItem(item);
if(hasItem())
{
if(getItem().getDecodeConfiguration() instanceof DecodeConfigAM)
{
DecodeConfigAM config = (DecodeConfigAM)getItem().getDecodeConfiguration();
mCheckBoxRecordAudio.setSelected(config.getRecordAudio());
mCheckBoxRecordAudio.setEnabled(true);
setModified(false);
}
else
{
setModified(true);
}
}
else
{
mCheckBoxRecordAudio.setEnabled(false);
setModified(false);
}
}
@Override
public void save()
{
if(hasItem() && isModified())
{
DecodeConfigAM config = new DecodeConfigAM();
config.setRecordAudio(mCheckBoxRecordAudio.isSelected());
getItem().setDecodeConfiguration(config);
}
setModified(false);
}
}

View File

@@ -1,20 +1,24 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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/>
******************************************************************************/
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
*
*/
package io.github.dsheirer.module.decode.config;
import com.fasterxml.jackson.annotation.JsonSubTypes;
@@ -23,39 +27,40 @@ import io.github.dsheirer.controller.config.Configuration;
import io.github.dsheirer.module.decode.DecoderType;
import java.util.ArrayList;
import java.util.List;
@JsonSubTypes.Type(value = AuxDecodeConfiguration.class, name = "auxDecodeConfiguration")
public class AuxDecodeConfiguration extends Configuration
{
ArrayList<DecoderType> mAuxDecoders = new ArrayList<DecoderType>();
public AuxDecodeConfiguration()
{
}
private List<DecoderType> mAuxDecoders = new ArrayList<DecoderType>();
@JacksonXmlProperty(isAttribute = false, localName = "aux_decoder")
public ArrayList<DecoderType> getAuxDecoders()
{
return mAuxDecoders;
}
public void setAuxDecoders( ArrayList<DecoderType> decoders )
{
mAuxDecoders = decoders;
}
public void addAuxDecoder( DecoderType decoder )
{
mAuxDecoders.add( decoder );
}
public void removeAuxDecoder( DecoderType decoder )
{
mAuxDecoders.remove( decoder );
}
public void clearAuxDecoders()
{
mAuxDecoders.clear();
}
public AuxDecodeConfiguration()
{
}
@JacksonXmlProperty(isAttribute = false, localName = "aux_decoder")
public List<DecoderType> getAuxDecoders()
{
return mAuxDecoders;
}
public void setAuxDecoders(List<DecoderType> decoders)
{
mAuxDecoders = decoders;
}
public void addAuxDecoder(DecoderType decoder)
{
mAuxDecoders.add(decoder);
}
public void removeAuxDecoder(DecoderType decoder)
{
mAuxDecoders.remove(decoder);
}
public void clearAuxDecoders()
{
mAuxDecoders.clear();
}
}

View File

@@ -76,7 +76,7 @@ public class DecodeEventModel extends AbstractTableModel implements Listener<IDe
fireTableCellUpdated(row, COLUMN_TIME);
}
}
else if(preferenceType == PreferenceType.IDENTIFIER)
else if(preferenceType == PreferenceType.TALKGROUP_FORMAT)
{
for(int row = 0; row < mEvents.size(); row++)
{

View File

@@ -102,7 +102,7 @@ public class DecodeEventPanel extends JPanel implements Listener<ProcessingChain
@Subscribe
public void preferenceUpdated(PreferenceType preferenceType)
{
if(preferenceType == PreferenceType.DECODE_EVENT || preferenceType == PreferenceType.IDENTIFIER)
if(preferenceType == PreferenceType.DECODE_EVENT || preferenceType == PreferenceType.TALKGROUP_FORMAT)
{
EventQueue.invokeLater(() -> mTimestampCellRenderer.updatePreferences());
}

View File

@@ -1,113 +0,0 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.module.decode.ltrnet;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EditorValidationException;
import io.github.dsheirer.gui.editor.ValidatingEditor;
import io.github.dsheirer.message.MessageDirection;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LTRNetDecoderEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
private JComboBox<MessageDirection> mComboDirection;
public LTRNetDecoderEditor()
{
init();
}
private void init()
{
setLayout(new MigLayout("insets 0 0 0 0,wrap 4", "[right][grow,fill][right][grow,fill]", ""));
mComboDirection = new JComboBox<MessageDirection>();
mComboDirection.setModel(new DefaultComboBoxModel<MessageDirection>(MessageDirection.values()));
mComboDirection.setSelectedItem(MessageDirection.OSW);
mComboDirection.setEnabled(false);
mComboDirection.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(new JLabel("Format:"));
add(mComboDirection);
}
@Override
public void validate(Editor<Channel> editor) throws EditorValidationException
{
//No validation
}
@Override
public void setItem(Channel item)
{
super.setItem(item);
if(hasItem())
{
mComboDirection.setEnabled(true);
DecodeConfiguration config = getItem().getDecodeConfiguration();
if(config instanceof DecodeConfigLTRNet)
{
DecodeConfigLTRNet ltr = (DecodeConfigLTRNet)config;
mComboDirection.setSelectedItem(ltr.getMessageDirection());
setModified(false);
}
else
{
mComboDirection.setSelectedItem(MessageDirection.OSW);
setModified(true);
}
}
else
{
mComboDirection.setEnabled(false);
setModified(false);
}
}
@Override
public void save()
{
if(hasItem() && isModified())
{
DecodeConfigLTRNet ltr = new DecodeConfigLTRNet();
ltr.setMessageDirection((MessageDirection)mComboDirection.getSelectedItem());
getItem().setDecodeConfiguration(ltr);
}
setModified(false);
}
}

View File

@@ -73,7 +73,8 @@ public abstract class LtrNetMessage extends Message
{
if(mTalkgroup == null)
{
mTalkgroup = LTRTalkgroup.create((getHomeRepeater(getMessage()) << 8) + getGroup(getMessage()));
mTalkgroup = LTRTalkgroup.create((getArea(getMessage()) << 13) + (getHomeRepeater(getMessage()) << 8) +
getGroup(getMessage()));
}
return mTalkgroup;

View File

@@ -35,7 +35,7 @@ public class DecodeConfigLTRStandard extends DecodeConfiguration
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
public DecoderType getDecoderType()
{
return DecoderType.LTR_STANDARD;
return DecoderType.LTR;
}

View File

@@ -61,7 +61,7 @@ public class LTRStandardDecoder extends Decoder implements IReusableBufferListen
@Override
public DecoderType getDecoderType()
{
return DecoderType.LTR_STANDARD;
return DecoderType.LTR;
}
@Override

View File

@@ -1,112 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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.module.decode.ltrstandard;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EditorValidationException;
import io.github.dsheirer.gui.editor.ValidatingEditor;
import io.github.dsheirer.message.MessageDirection;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LTRStandardDecoderEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
private JComboBox<MessageDirection> mComboDirection;
public LTRStandardDecoderEditor()
{
init();
}
private void init()
{
setLayout(new MigLayout("insets 0 0 0 0,wrap 4", "[right][grow,fill][right][grow,fill]", ""));
mComboDirection = new JComboBox<MessageDirection>();
mComboDirection.setModel(new DefaultComboBoxModel<MessageDirection>(MessageDirection.values()));
mComboDirection.setSelectedItem(MessageDirection.OSW);
mComboDirection.setEnabled(false);
mComboDirection.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(new JLabel("Format:"));
add(mComboDirection);
}
@Override
public void validate(Editor<Channel> editor) throws EditorValidationException
{
}
@Override
public void setItem(Channel item)
{
super.setItem(item);
if(hasItem())
{
mComboDirection.setEnabled(true);
DecodeConfiguration config = getItem().getDecodeConfiguration();
if(config instanceof DecodeConfigLTRStandard)
{
DecodeConfigLTRStandard ltr = (DecodeConfigLTRStandard)config;
mComboDirection.setSelectedItem(ltr.getMessageDirection());
setModified(false);
}
else
{
mComboDirection.setSelectedItem(MessageDirection.OSW);
setModified(true);
}
}
else
{
mComboDirection.setEnabled(false);
setModified(false);
}
}
@Override
public void save()
{
if(hasItem() && isModified())
{
DecodeConfigLTRStandard ltr = new DecodeConfigLTRStandard();
ltr.setMessageDirection((MessageDirection)mComboDirection.getSelectedItem());
getItem().setDecodeConfiguration(ltr);
}
setModified(false);
}
}

View File

@@ -39,7 +39,7 @@ import io.github.dsheirer.module.decode.ltrstandard.channel.LtrChannel;
import io.github.dsheirer.module.decode.ltrstandard.message.Call;
import io.github.dsheirer.module.decode.ltrstandard.message.CallEnd;
import io.github.dsheirer.module.decode.ltrstandard.message.Idle;
import io.github.dsheirer.module.decode.ltrstandard.message.LTRStandardMessage;
import io.github.dsheirer.module.decode.ltrstandard.message.LTRMessage;
import io.github.dsheirer.protocol.Protocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -70,15 +70,15 @@ public class LTRStandardDecoderState extends DecoderState
@Override
public DecoderType getDecoderType()
{
return DecoderType.LTR_STANDARD;
return DecoderType.LTR;
}
@Override
public void receive(IMessage message)
{
if(message.isValid() && message instanceof LTRStandardMessage)
if(message.isValid() && message instanceof LTRMessage)
{
switch(((LTRStandardMessage)message).getMessageType())
switch(((LTRMessage)message).getMessageType())
{
case CALL:
if(message instanceof Call)
@@ -98,7 +98,7 @@ public class LTRStandardDecoderState extends DecoderState
getIdentifierCollection().remove(IdentifierClass.USER);
getIdentifierCollection().update(start.getTalkgroup());
mCurrentCallEvent = DecodeEvent.builder(start.getTimestamp())
.protocol(Protocol.LTR_STANDARD)
.protocol(Protocol.LTR)
.identifiers(getIdentifierCollection().copyOf())
.channel(getCurrentChannel())
.eventDescription("Call")
@@ -201,7 +201,7 @@ public class LTRStandardDecoderState extends DecoderState
if(mLCNTracker.getCurrentChannel() != original)
{
getIdentifierCollection().update(DecoderLogicalChannelNameIdentifier
.create(String.valueOf(mLCNTracker.getCurrentChannel()), Protocol.LTR_STANDARD));
.create(String.valueOf(mLCNTracker.getCurrentChannel()), Protocol.LTR));
LtrChannel ltrChannel = new LtrChannel(mLCNTracker.getCurrentChannel());

View File

@@ -23,8 +23,7 @@ package io.github.dsheirer.module.decode.ltrstandard;
import io.github.dsheirer.filter.Filter;
import io.github.dsheirer.filter.FilterElement;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.module.decode.ltrstandard.message.LTRStandardMessage;
import io.github.dsheirer.module.decode.mdc1200.MDCMessageType;
import io.github.dsheirer.module.decode.ltrstandard.message.LTRMessage;
import java.util.*;
@@ -47,7 +46,7 @@ public class LTRStandardMessageFilter extends Filter<IMessage>
{
if(mEnabled && canProcess(message))
{
LTRStandardMessage ltr = (LTRStandardMessage)message;
LTRMessage ltr = (LTRMessage)message;
if(mElements.containsKey(ltr.getMessageType()))
{
@@ -60,7 +59,7 @@ public class LTRStandardMessageFilter extends Filter<IMessage>
public boolean canProcess(IMessage message)
{
return message instanceof LTRStandardMessage;
return message instanceof LTRMessage;
}
@Override

View File

@@ -27,7 +27,7 @@ import io.github.dsheirer.message.MessageDirection;
import io.github.dsheirer.module.decode.ltrstandard.message.Call;
import io.github.dsheirer.module.decode.ltrstandard.message.CallEnd;
import io.github.dsheirer.module.decode.ltrstandard.message.Idle;
import io.github.dsheirer.module.decode.ltrstandard.message.LTRStandardMessage;
import io.github.dsheirer.module.decode.ltrstandard.message.LTRMessage;
import io.github.dsheirer.module.decode.ltrstandard.message.UnknownMessage;
import io.github.dsheirer.sample.Listener;
@@ -62,12 +62,12 @@ public class LTRStandardMessageProcessor implements Listener<CorrectedBinaryMess
if(crc.passes())
{
LTRStandardMessage message;
LTRMessage message;
int channel = binaryMessage.getInt(LTRStandardMessage.CHANNEL);
int home = binaryMessage.getInt(LTRStandardMessage.HOME_REPEATER);
int free = binaryMessage.getInt(LTRStandardMessage.FREE);
int group = binaryMessage.getInt(LTRStandardMessage.GROUP);
int channel = binaryMessage.getInt(LTRMessage.CHANNEL);
int home = binaryMessage.getInt(LTRMessage.HOME_REPEATER);
int free = binaryMessage.getInt(LTRMessage.FREE);
int group = binaryMessage.getInt(LTRMessage.GROUP);
if(isValidChannel(channel) && isValidChannel(home) && isValidChannel(free))
{

View File

@@ -83,7 +83,7 @@ public class LtrChannel implements IChannelDescriptor, Comparable<LtrChannel>
@Override
public Protocol getProtocol()
{
return Protocol.LTR_STANDARD;
return Protocol.LTR;
}
@Override

View File

@@ -28,7 +28,7 @@ import io.github.dsheirer.module.decode.ltrstandard.LtrStandardMessageType;
import java.util.ArrayList;
import java.util.List;
public class Call extends LTRStandardMessage
public class Call extends LTRMessage
{
private List<Identifier> mIdentifiers;

View File

@@ -28,7 +28,7 @@ import io.github.dsheirer.module.decode.ltrstandard.LtrStandardMessageType;
import java.util.ArrayList;
import java.util.List;
public class CallEnd extends LTRStandardMessage
public class CallEnd extends LTRMessage
{
private List<Identifier> mIdentifiers;

View File

@@ -31,7 +31,7 @@ import java.util.List;
/**
* Indicates the repeater is IDLE and available for use
*/
public class Idle extends LTRStandardMessage
public class Idle extends LTRMessage
{
public Idle(CorrectedBinaryMessage message, MessageDirection direction, CRC crc)
{

View File

@@ -30,7 +30,7 @@ import io.github.dsheirer.protocol.Protocol;
/**
* LTR Standard Base Message
*/
public abstract class LTRStandardMessage extends Message
public abstract class LTRMessage extends Message
{
public static final int[] SYNC = {0, 1, 2, 3, 4, 5, 6, 7, 8};
public static final int[] AREA = {9};
@@ -51,7 +51,7 @@ public abstract class LTRStandardMessage extends Message
* @param direction of the messsage, ISW or OSW
* @param crc error check
*/
public LTRStandardMessage(CorrectedBinaryMessage message, MessageDirection direction, CRC crc)
public LTRMessage(CorrectedBinaryMessage message, MessageDirection direction, CRC crc)
{
mMessage = message;
mMessageDirection = direction;
@@ -134,7 +134,7 @@ public abstract class LTRStandardMessage extends Message
{
if(mTalkgroup == null)
{
mTalkgroup = LTRTalkgroup.create((getHomeRepeater() << 8) + getGroup());
mTalkgroup = LTRTalkgroup.create((getArea() << 13) + (getHomeRepeater() << 8) + getGroup());
}
return mTalkgroup;
@@ -143,6 +143,6 @@ public abstract class LTRStandardMessage extends Message
@Override
public Protocol getProtocol()
{
return Protocol.LTR_STANDARD;
return Protocol.LTR;
}
}

View File

@@ -31,7 +31,7 @@ import java.util.List;
/**
* Unknown message type
*/
public class UnknownMessage extends LTRStandardMessage
public class UnknownMessage extends LTRMessage
{
public UnknownMessage(CorrectedBinaryMessage message, MessageDirection direction, CRC crc)
{

View File

@@ -1,263 +0,0 @@
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
*
*/
package io.github.dsheirer.module.decode.mpt1327;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.controller.channel.map.ChannelMap;
import io.github.dsheirer.controller.channel.map.ChannelMapManagerFrame;
import io.github.dsheirer.controller.channel.map.ChannelMapModel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EditorValidationException;
import io.github.dsheirer.gui.editor.ValidatingEditor;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.List;
public class MPT1327DecoderEditor extends ValidatingEditor<Channel>
{
private final static Logger mLog = LoggerFactory.getLogger(MPT1327DecoderEditor.class);
private static final long serialVersionUID = 1L;
private JComboBox<ChannelMap> mComboChannelMaps;
private JLabel mCallTimeoutLabel;
private JSlider mCallTimeout;
private JLabel mTrafficChannelPoolSizeLabel;
private JSlider mTrafficChannelPoolSize;
private ChannelMapModel mChannelMapModel;
public MPT1327DecoderEditor(ChannelMapModel channelMapModel)
{
mChannelMapModel = channelMapModel;
init();
}
private void init()
{
setLayout(new MigLayout("insets 0 0 0 0,wrap 4", "[right][grow,fill][right][grow,fill]", ""));
mComboChannelMaps = new JComboBox<ChannelMap>();
refreshChannelMaps();
mComboChannelMaps.setEnabled(false);
mComboChannelMaps.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(new JLabel("Channel Map:"));
add(mComboChannelMaps);
JButton channelMaps = new JButton("Channel Map Editor");
channelMaps.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
final ChannelMapManagerFrame manager = new ChannelMapManagerFrame(mChannelMapModel);
manager.addWindowListener(new WindowAdapter()
{
@Override
public void windowClosed(WindowEvent e)
{
super.windowClosed(e);
mLog.debug("Refreshing channel maps combo box");
refreshChannelMaps();
}
});
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
manager.setVisible(true);
}
});
}
});
add(channelMaps, "span 2,grow");
mTrafficChannelPoolSize = new JSlider(JSlider.HORIZONTAL, DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MINIMUM,
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MAXIMUM, DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT);
mTrafficChannelPoolSize.setEnabled(false);
mTrafficChannelPoolSize.setMajorTickSpacing(10);
mTrafficChannelPoolSize.setMinorTickSpacing(5);
mTrafficChannelPoolSize.setPaintTicks(true);
mTrafficChannelPoolSizeLabel = new JLabel("Traffic Pool: " + mTrafficChannelPoolSize.getValue() + " ");
mTrafficChannelPoolSize.addChangeListener(new ChangeListener()
{
@Override
public void stateChanged(ChangeEvent e)
{
mTrafficChannelPoolSizeLabel.setText("Traffic Pool: " + mTrafficChannelPoolSize.getValue());
setModified(true);
}
});
add(mTrafficChannelPoolSizeLabel);
add(mTrafficChannelPoolSize);
mCallTimeout = new JSlider(JSlider.HORIZONTAL, DecodeConfiguration.CALL_TIMEOUT_MINIMUM,
DecodeConfiguration.CALL_TIMEOUT_MAXIMUM, DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS);
mCallTimeout.setEnabled(false);
mCallTimeout.setMajorTickSpacing(100);
mCallTimeout.setMinorTickSpacing(50);
mCallTimeout.setPaintTicks(true);
mCallTimeoutLabel = new JLabel("Timeout: " + mCallTimeout.getValue() + " ");
mCallTimeout.addChangeListener(new ChangeListener()
{
@Override
public void stateChanged(ChangeEvent e)
{
mCallTimeoutLabel.setText("Timeout: " + mCallTimeout.getValue());
setModified(true);
}
});
add(mCallTimeoutLabel);
add(mCallTimeout);
}
private void refreshChannelMaps()
{
List<ChannelMap> maps = mChannelMapModel.getChannelMaps();
ChannelMap[] mapArray = new ChannelMap[maps.size() + 1];
int index = 1;
for(ChannelMap channelMap: maps)
{
mapArray[index++] = channelMap;
}
mComboChannelMaps.setModel(new DefaultComboBoxModel<ChannelMap>(mapArray));
}
@Override
public void save()
{
if(hasItem() && isModified())
{
DecodeConfigMPT1327 mpt = new DecodeConfigMPT1327();
mpt.setTrafficChannelPoolSize(mTrafficChannelPoolSize.getValue());
mpt.setCallTimeout(mCallTimeout.getValue());
if(mComboChannelMaps.getSelectedItem() != null)
{
ChannelMap map = (ChannelMap)mComboChannelMaps.getSelectedItem();
mpt.setChannelMapName(map.getName());
}
getItem().setDecodeConfiguration(mpt);
}
setModified(false);
}
@Override
public void validate(Editor<Channel> editor) throws EditorValidationException
{
//No validation required
}
private void setControlsEnabled(boolean enabled)
{
if(mComboChannelMaps.isEnabled() != enabled)
{
mComboChannelMaps.setEnabled(enabled);
}
if(mTrafficChannelPoolSize.isEnabled() != enabled)
{
mTrafficChannelPoolSize.setEnabled(enabled);
}
if(mCallTimeout.isEnabled() != enabled)
{
mCallTimeout.setEnabled(enabled);
}
}
@Override
public void setItem(Channel item)
{
super.setItem(item);
if(hasItem())
{
setControlsEnabled(true);
DecodeConfiguration config = getItem().getDecodeConfiguration();
if(config instanceof DecodeConfigMPT1327)
{
DecodeConfigMPT1327 mpt = (DecodeConfigMPT1327)config;
ChannelMap map = mChannelMapModel.getChannelMap(mpt.getChannelMapName());
if(map != null)
{
mComboChannelMaps.setSelectedItem(map);
}
mTrafficChannelPoolSize.setValue(mpt.getTrafficChannelPoolSize());
mCallTimeout.setValue(mpt.getCallTimeout());
setModified(false);
}
else
{
mTrafficChannelPoolSize.setValue(DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT);
mCallTimeout.setValue(DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS);
setModified(true);
}
}
else
{
setControlsEnabled(false);
setModified(false);
}
}
}

View File

@@ -35,6 +35,9 @@ import io.github.dsheirer.protocol.Protocol;
*/
public class MPT1327Talkgroup extends TalkgroupIdentifier
{
public static final int PREFIX_MASK = 0xFE000;
public static final int IDENT_MASK = 0x1FFF;
public MPT1327Talkgroup(Integer value, Role role)
{
super(value, role);
@@ -85,7 +88,7 @@ public class MPT1327Talkgroup extends TalkgroupIdentifier
{
if(0 < ident && ident <= 8100)
{
return new MPT1327Talkgroup(((prefix << 13) + ident), Role.TO);
return new MPT1327Talkgroup(encode(prefix, ident), Role.TO);
}
else
{
@@ -93,4 +96,24 @@ public class MPT1327Talkgroup extends TalkgroupIdentifier
return new MPT1327Talkgroup(ident, Role.TO);
}
}
public static MPT1327Talkgroup createTo(int value)
{
return new MPT1327Talkgroup(value, Role.TO);
}
public static int encode(int prefix, int ident)
{
return (prefix << 13) + ident;
}
public static int getPrefix(int value)
{
return (value & PREFIX_MASK) >> 13;
}
public static int getIdent(int value)
{
return value & IDENT_MASK;
}
}

View File

@@ -1,136 +0,0 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.module.decode.nbfm;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EditorValidationException;
import io.github.dsheirer.gui.editor.ValidatingEditor;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class NBFMDecoderEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
private JComboBox<DecodeConfigNBFM.Bandwidth> mComboBandwidth;
private JCheckBox mCheckBoxRecordAudio;
public NBFMDecoderEditor()
{
init();
}
private void init()
{
setLayout(new MigLayout("insets 0 0 0 0,wrap 3", "[][][]", ""));
mComboBandwidth = new JComboBox<>();
mComboBandwidth.setModel(new DefaultComboBoxModel<DecodeConfigNBFM.Bandwidth>(
DecodeConfigNBFM.Bandwidth.values()));
mComboBandwidth.setEnabled(false);
mComboBandwidth.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(new JLabel("Bandwidth:"));
add(mComboBandwidth);
mCheckBoxRecordAudio = new JCheckBox("Record Audio");
mCheckBoxRecordAudio.setEnabled(false);
mCheckBoxRecordAudio.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mCheckBoxRecordAudio);
}
@Override
public void validate(Editor<Channel> editor) throws EditorValidationException
{
//No validation
}
@Override
public void save()
{
if(hasItem() && isModified())
{
DecodeConfigNBFM nbfm = new DecodeConfigNBFM();
nbfm.setBandwidth((DecodeConfigNBFM.Bandwidth)mComboBandwidth.getSelectedItem());
nbfm.setRecordAudio(mCheckBoxRecordAudio.isSelected());
getItem().setDecodeConfiguration(nbfm);
}
setModified(false);
}
private void setControlsEnabled(boolean enabled)
{
mComboBandwidth.setEnabled(enabled);
mCheckBoxRecordAudio.setEnabled(enabled);
}
@Override
public void setItem(Channel item)
{
super.setItem(item);
if(hasItem())
{
setControlsEnabled(true);
DecodeConfiguration config = getItem().getDecodeConfiguration();
if(config instanceof DecodeConfigNBFM)
{
DecodeConfigNBFM nbfm = (DecodeConfigNBFM)config;
mComboBandwidth.setSelectedItem(nbfm.getBandwidth());
mCheckBoxRecordAudio.setSelected(nbfm.getRecordAudio());
setModified(false);
}
else
{
setModified(true);
}
}
else
{
setControlsEnabled(false);
setModified(false);
}
}
}

View File

@@ -19,7 +19,6 @@
package io.github.dsheirer.module.decode.p25.audio;
import com.google.common.base.Joiner;
import io.github.dsheirer.alias.AliasList;
import io.github.dsheirer.audio.codec.mbe.AmbeAudioModule;
import io.github.dsheirer.audio.squelch.SquelchState;
@@ -29,7 +28,10 @@ import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.IdentifierUpdateNotification;
import io.github.dsheirer.identifier.IdentifierUpdateProvider;
import io.github.dsheirer.identifier.Role;
import io.github.dsheirer.identifier.tone.AmbeTone;
import io.github.dsheirer.identifier.tone.P25ToneIdentifier;
import io.github.dsheirer.identifier.tone.Tone;
import io.github.dsheirer.identifier.tone.ToneSequence;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.module.decode.p25.phase2.message.EncryptionSynchronizationSequence;
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.PushToTalk;
@@ -247,15 +249,15 @@ public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdat
*/
public class ToneMetadataProcessor
{
private List<ToneMetadata> mToneMetadata = new ArrayList<>();
private ToneMetadata mCurrentToneMetadata;
private List<Tone> mTones = new ArrayList<>();
private Tone mCurrentTone;
/**
* Resets or clears any accumulated call tone metadata to prepare for the next call.
* Resets or clears any accumulated call tone sequences to prepare for the next call.
*/
public void reset()
{
mToneMetadata.clear();
mTones.clear();
}
/**
@@ -271,18 +273,22 @@ public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdat
return null;
}
if(mCurrentToneMetadata != null && mCurrentToneMetadata.matches(type, value))
AmbeTone tone = AmbeTone.fromValues(type, value);
if(tone == AmbeTone.INVALID)
{
mCurrentToneMetadata.incrementCount();
}
else
{
mCurrentToneMetadata = new ToneMetadata(type, value);
mToneMetadata.add(mCurrentToneMetadata);
mCurrentToneMetadata.incrementCount();
return null;
}
return P25ToneIdentifier.create(Joiner.on(",").join(mToneMetadata));
if(mCurrentTone == null || mCurrentTone.getAmbeTone() != tone)
{
mCurrentTone = new Tone(tone);
mTones.add(mCurrentTone);
}
mCurrentTone.incrementDuration();
return P25ToneIdentifier.create(new ToneSequence(new ArrayList<>(mTones)));
}
/**
@@ -290,85 +296,7 @@ public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdat
*/
public void closeMetadata()
{
mCurrentToneMetadata = null;
}
}
/**
* Metadata about the tone type being transmitted and the duration.
*
* Note: each AMBE frame is 20 milliseconds in duration, so total duration is the count of 20 ms tone frames
* of the same metadata type.
*/
public class ToneMetadata
{
private String mType;
private String mValue;
private int mCount;
/**
* Constructs an instance
* @param type of tone
* @param value of the tone
*/
public ToneMetadata(String type, String value)
{
mType = type;
mValue = value;
mCount = 0;
}
/**
* Indicates if this tone metadata matches the tone metadata represented by the arguments
* @param type of tone
* @param value of tone
* @return true if they match
*/
public boolean matches(String type, String value)
{
return type != null && value != null && type.matches(mType) && value.matches(mValue);
}
/**
* Type of tone
*/
public String getType()
{
return mType;
}
/**
* Value of tone
*/
public String getValue()
{
return mValue;
}
/**
* Number of times this tone has occurred sequentially
*/
public int getCount()
{
return mCount;
}
/**
* Increments the count of the number of sequential frames that contained the tone
*/
public void incrementCount()
{
mCount++;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(mType);
sb.append(" ").append(mValue);
sb.append(" (").append(mCount * 20).append("ms)");
return sb.toString();
mCurrentTone = null;
}
}

View File

@@ -1,21 +1,23 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
* 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.module.decode.p25.phase1;
@@ -32,7 +34,7 @@ public class DecodeConfigP25Phase1 extends DecodeConfiguration
private int mCallTimeout = 1;
private int mTrafficChannelPoolSize = TRAFFIC_CHANNEL_LIMIT_DEFAULT;
private boolean mIgnoreDataCalls = true;
private boolean mIgnoreDataCalls = false;
public DecodeConfigP25Phase1()
{

View File

@@ -1,221 +0,0 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EditorValidationException;
import io.github.dsheirer.gui.editor.ValidatingEditor;
import io.github.dsheirer.module.decode.AuxDecodeConfigurationEditor;
import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.source.SourceConfigurationEditor;
import io.github.dsheirer.source.config.SourceConfigTuner;
import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency;
import io.github.dsheirer.source.config.SourceConfiguration;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class P25P1DecoderEditor extends ValidatingEditor<Channel>
{
private final static Logger mLog = LoggerFactory.getLogger(P25P1DecoderEditor.class);
private static final long serialVersionUID = 1L;
private JComboBox<P25P1DecoderLSM.Modulation> mComboModulation;
private JCheckBox mIgnoreDataCalls;
private JLabel mTrafficChannelPoolSizeLabel;
private JSlider mTrafficChannelPoolSize;
public P25P1DecoderEditor()
{
init();
}
private void init()
{
setLayout(new MigLayout("insets 0 0 0 0,wrap 3", "[right][grow,fill][]", ""));
mComboModulation = new JComboBox<P25P1DecoderLSM.Modulation>();
mComboModulation.setModel(new DefaultComboBoxModel<P25P1DecoderLSM.Modulation>(
P25P1DecoderLSM.Modulation.values()));
mComboModulation.setEnabled(false);
mComboModulation.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(new JLabel("Modulation:"));
add(mComboModulation);
mIgnoreDataCalls = new JCheckBox("Ignore Data Calls");
mIgnoreDataCalls.setEnabled(false);
mIgnoreDataCalls.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mIgnoreDataCalls);
mTrafficChannelPoolSize = new JSlider(JSlider.HORIZONTAL, DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MINIMUM,
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MAXIMUM, DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT);
mTrafficChannelPoolSize.setEnabled(false);
mTrafficChannelPoolSize.setMajorTickSpacing(10);
mTrafficChannelPoolSize.setMinorTickSpacing(5);
mTrafficChannelPoolSize.setPaintTicks(true);
mTrafficChannelPoolSize.addChangeListener(new ChangeListener()
{
@Override
public void stateChanged(ChangeEvent e)
{
mTrafficChannelPoolSizeLabel.setText("Traffic Pool: " + mTrafficChannelPoolSize.getValue());
setModified(true);
}
});
mTrafficChannelPoolSizeLabel = new JLabel("Traffic Pool: " + mTrafficChannelPoolSize.getValue() + " ");
add(mTrafficChannelPoolSizeLabel);
add(mTrafficChannelPoolSize);
}
@Override
public void save()
{
if(hasItem() && isModified())
{
DecodeConfigP25Phase1 p25 = new DecodeConfigP25Phase1();
p25.setModulation((P25P1Decoder.Modulation)mComboModulation.getSelectedItem());
p25.setIgnoreDataCalls(mIgnoreDataCalls.isSelected());
p25.setTrafficChannelPoolSize(mTrafficChannelPoolSize.getValue());
getItem().setDecodeConfiguration(p25);
}
setModified(false);
}
@Override
public void validate(Editor<Channel> editor) throws EditorValidationException
{
/**
* Enforce CQPSK modulation uses a Tuner Source for I/Q sample data
*/
if(editor instanceof SourceConfigurationEditor)
{
SourceConfiguration config = ((SourceConfigurationEditor)editor).getSourceConfiguration();
if(!(config instanceof SourceConfigTuner || config instanceof SourceConfigTunerMultipleFrequency))
{
throw new EditorValidationException(editor,
"<html><body width='175'><h3>LSM Simulcast</h3>"
+ "<p>P25 LSM Simulcast decoder can only be used with "
+ "a tuner source. Please change the Source to use a tuner"
+ " or change the P25 Decoder to C4FM modulation</p>");
}
}
else if(editor instanceof AuxDecodeConfigurationEditor)
{
AuxDecodeConfiguration config = ((AuxDecodeConfigurationEditor)editor).getConfiguration();
if(config != null && !config.getAuxDecoders().isEmpty())
{
throw new EditorValidationException(editor,
"<html><body width='175'><h3>Auxilary Decoders</h3>"
+ "<p>The auxiliary decoders work with analog audio and are not "
+ "compatible with the P25 Decoder. Please uncheck any auxiliary "
+ "decoders that you have selected for this channel</p>");
}
}
}
private void setControlsEnabled(boolean enabled)
{
if(mComboModulation.isEnabled() != enabled)
{
mComboModulation.setEnabled(enabled);
}
if(mTrafficChannelPoolSize.isEnabled() != enabled)
{
mTrafficChannelPoolSize.setEnabled(enabled);
}
if(mIgnoreDataCalls.isEnabled() != enabled)
{
mIgnoreDataCalls.setEnabled(enabled);
}
}
@Override
public void setItem(Channel item)
{
super.setItem(item);
if(hasItem())
{
setControlsEnabled(true);
DecodeConfiguration config = getItem().getDecodeConfiguration();
if(config instanceof DecodeConfigP25Phase1)
{
DecodeConfigP25Phase1 p25 = (DecodeConfigP25Phase1)config;
mComboModulation.setSelectedItem(p25.getModulation());
mIgnoreDataCalls.setSelected(p25.getIgnoreDataCalls());
mTrafficChannelPoolSize.setValue(p25.getTrafficChannelPoolSize());
setModified(false);
}
else
{
mComboModulation.setSelectedItem(P25P1Decoder.Modulation.C4FM);
mIgnoreDataCalls.setSelected(false);
mTrafficChannelPoolSize.setValue(DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT);
setModified(true);
}
}
else
{
setControlsEnabled(false);
setModified(false);
}
}
}

View File

@@ -1,283 +0,0 @@
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
*
*/
package io.github.dsheirer.module.decode.p25.phase2;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EditorValidationException;
import io.github.dsheirer.gui.editor.ValidatingEditor;
import io.github.dsheirer.module.decode.AuxDecodeConfigurationEditor;
import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters;
import io.github.dsheirer.source.SourceConfigurationEditor;
import io.github.dsheirer.source.config.SourceConfigTuner;
import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency;
import io.github.dsheirer.source.config.SourceConfiguration;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.JCheckBox;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Editor panel for P25 Phase II decoder configuration
*/
public class P25P2DecoderEditor extends ValidatingEditor<Channel>
{
private final static Logger mLog = LoggerFactory.getLogger(P25P2DecoderEditor.class);
private static final long serialVersionUID = 1L;
private JCheckBox mAutoDetectCheckBox;
private JFormattedTextField mWacnText;
private JFormattedTextField mSystemText;
private JFormattedTextField mNacText;
public P25P2DecoderEditor()
{
init();
}
private void init()
{
setLayout(new MigLayout("insets 0 0 0 0,wrap 2", "[right][grow,fill]", ""));
mAutoDetectCheckBox = new JCheckBox("Auto-Detect System Settings");
mAutoDetectCheckBox.setToolTipText("Auto-detect WACN, SYSTEM and NAC for systems that broadcast this information.");
mAutoDetectCheckBox.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
mWacnText.setEnabled(!mAutoDetectCheckBox.isSelected());
mSystemText.setEnabled(!mAutoDetectCheckBox.isSelected());
mNacText.setEnabled(!mAutoDetectCheckBox.isSelected());
setModified(true);
}
});
add(new JLabel(" "));
add(mAutoDetectCheckBox);
DocumentModificationListener documentModificationListener = new DocumentModificationListener();
add(new JLabel("WACN:"));
mWacnText = new JFormattedTextField();
mWacnText.setToolTipText("Wide Area Communications Network (WACN) value in range: 0 - 1,048,575. Set to 0 for auto-detect");
mWacnText.setValue(Integer.valueOf(0));
mWacnText.getDocument().addDocumentListener(documentModificationListener);
add(mWacnText);
add(new JLabel("SYSTEM:"));
mSystemText = new JFormattedTextField();
mSystemText.setToolTipText("System code in range: 0 - 4,095. Set to 0 for auto-detect");
mSystemText.setValue(Integer.valueOf(0));
mSystemText.getDocument().addDocumentListener(documentModificationListener);
add(mSystemText);
add(new JLabel("NAC:"));
mNacText = new JFormattedTextField();
mSystemText.setToolTipText("Network Access Code (NAC): 0 - 4,095. Set to 0 for auto-detect");
mNacText.setValue(Integer.valueOf(0));
mNacText.getDocument().addDocumentListener(documentModificationListener);
add(mNacText);
}
@Override
public void save()
{
if(hasItem() && isModified())
{
DecodeConfigP25Phase2 p25 = new DecodeConfigP25Phase2();
p25.setAutoDetectScrambleParameters(mAutoDetectCheckBox.isSelected());
int wacn = ((Number)mWacnText.getValue()).intValue();
if(wacn < 0 || wacn > 0xFFFFF)
{
JOptionPane.showConfirmDialog(P25P2DecoderEditor.this, "WACN [" + wacn +
"] must be in range: 0 - 1,048,575. Please change and click 'Save' or a default value of 0 will " +
"be used", "WACN Value Error", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
wacn = 0;
}
int system = ((Number)mSystemText.getValue()).intValue();
if(system < 0 || system > 0xFFF)
{
JOptionPane.showConfirmDialog(P25P2DecoderEditor.this, "SYSTEM [" + system +
"] must be in range: 0 - 4,095. Please change and click 'Save' or a default value of 0 will " +
"be used", "SYSTEM Value Error", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
system = 0;
}
int nac = ((Number)mNacText.getValue()).intValue();
if(nac < 0 || nac > 0xFFF)
{
JOptionPane.showConfirmDialog(P25P2DecoderEditor.this, "NAC [" + nac +
"] must be in range: 0 - 4,095. Please change and click 'Save' or a default value of 0 will " +
"be used", "NAC Value Error", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
nac = 0;
}
if(wacn != 0 && system != 0 && nac != 0)
{
p25.setScrambleParameters(new ScrambleParameters(wacn, system, nac));
}
getItem().setDecodeConfiguration(p25);
}
setModified(false);
}
@Override
public void validate(Editor<Channel> editor) throws EditorValidationException
{
/**
* Enforce CQPSK modulation uses a Tuner Source for I/Q sample data
*/
if(editor instanceof SourceConfigurationEditor)
{
SourceConfiguration config = ((SourceConfigurationEditor)editor).getSourceConfiguration();
if(!(config instanceof SourceConfigTuner || config instanceof SourceConfigTunerMultipleFrequency))
{
throw new EditorValidationException(editor,
"<html><body width='175'><h3>LSM Simulcast</h3>"
+ "<p>P25 Phase II decoder can only be used with a tuner source.</p>");
}
}
else if(editor instanceof AuxDecodeConfigurationEditor)
{
AuxDecodeConfiguration config = ((AuxDecodeConfigurationEditor)editor).getConfiguration();
if(config != null && !config.getAuxDecoders().isEmpty())
{
throw new EditorValidationException(editor,
"<html><body width='175'><h3>Auxilary Decoders</h3>"
+ "<p>The auxiliary decoders work with analog audio and are not "
+ "compatible with the P25 Decoder. Please uncheck any auxiliary "
+ "decoders that you have selected for this channel</p>");
}
}
}
private void setControlsEnabled(boolean enabled)
{
mWacnText.setEnabled(enabled);
mSystemText.setEnabled(enabled);
mNacText.setEnabled(enabled);
mAutoDetectCheckBox.setEnabled(enabled);
}
@Override
public void setItem(Channel item)
{
super.setItem(item);
if(hasItem())
{
setControlsEnabled(true);
DecodeConfiguration config = getItem().getDecodeConfiguration();
if(config instanceof DecodeConfigP25Phase2)
{
DecodeConfigP25Phase2 p25 = (DecodeConfigP25Phase2)config;
ScrambleParameters scrambleParameters = p25.getScrambleParameters();
if(scrambleParameters != null)
{
mWacnText.setValue(scrambleParameters.getWACN());
mSystemText.setValue(scrambleParameters.getSystem());
mNacText.setValue(scrambleParameters.getNAC());
}
boolean autoDetect = p25.isAutoDetectScrambleParameters();
mAutoDetectCheckBox.setSelected(autoDetect);
mWacnText.setEnabled(!autoDetect);
mSystemText.setEnabled(!autoDetect);
mNacText.setEnabled(!autoDetect);
setModified(false);
}
else
{
mAutoDetectCheckBox.setSelected(false);
mWacnText.setEnabled(true);
mWacnText.setValue(0);
mSystemText.setEnabled(true);
mSystemText.setValue(0);
mNacText.setEnabled(true);
mNacText.setValue(0);
setModified(true);
}
}
else
{
mWacnText.setValue(0);
mSystemText.setValue(0);
mNacText.setValue(0);
mAutoDetectCheckBox.setSelected(false);
setModified(false);
setControlsEnabled(false);
}
}
/**
* Document change listener that sets the editor to modified (true) on any change to the document.
*/
public class DocumentModificationListener implements DocumentListener
{
@Override
public void insertUpdate(DocumentEvent e)
{
setModified(true);
}
@Override
public void removeUpdate(DocumentEvent e)
{
setModified(true);
}
@Override
public void changedUpdate(DocumentEvent e)
{
setModified(true);
}
}
}

View File

@@ -1,93 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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.module.decode.passport;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EditorValidationException;
import io.github.dsheirer.gui.editor.ValidatingEditor;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import javax.swing.JLabel;
public class PassportDecoderEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
public PassportDecoderEditor()
{
init();
}
private void init()
{
setLayout(new MigLayout("insets 0 0 0 0,wrap 2", "[right][grow,fill]", ""));
add( new JLabel( "Passport Decoder" ) );
}
@Override
public void validate(Editor<Channel> editor) throws EditorValidationException
{
//No validation
}
@Override
public void save()
{
if(hasItem() && isModified())
{
DecodeConfigPassport passport = new DecodeConfigPassport();
getItem().setDecodeConfiguration(passport);
}
setModified(false);
}
private void setControlsEnabled(boolean enabled)
{
}
@Override
public void setItem(Channel item)
{
super.setItem(item);
if(hasItem())
{
setControlsEnabled(true);
DecodeConfiguration config = getItem().getDecodeConfiguration();
if(config instanceof DecodeConfigPassport)
{
DecodeConfigPassport passport = (DecodeConfigPassport)config;
setModified(false);
}
else
{
setModified(true);
}
}
else
{
setControlsEnabled(false);
setModified(false);
}
}
}

View File

@@ -34,6 +34,7 @@ import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.message.MessageType;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.event.DecodeEvent;
import io.github.dsheirer.module.decode.passport.identifier.PassportRadioId;
import io.github.dsheirer.module.decode.passport.identifier.PassportTalkgroup;
import io.github.dsheirer.protocol.Protocol;
import org.slf4j.Logger;
@@ -57,7 +58,7 @@ public class PassportDecoderState extends DecoderState
private Set<PassportTalkgroup> mTalkgroupsFirstHeard = new HashSet<>();
private Set<PassportTalkgroup> mTalkgroups = new TreeSet<>();
private Set<PassportTalkgroup> mMobileIDs = new TreeSet<>();
private Set<PassportRadioId> mMobileIDs = new TreeSet<>();
private Map<Integer,Long> mSiteLCNs = new HashMap<>();
private Map<Integer,Long> mNeighborLCNs = new HashMap<>();
private Map<Integer,DecodeEvent> mDetectedCalls = new HashMap<>();
@@ -209,7 +210,7 @@ public class PassportDecoderState extends DecoderState
broadcast(new DecoderStateEvent(this, Event.END, State.CALL));
break;
case ID_RDIO:
PassportTalkgroup mobileId = passport.getFromIdentifier();
PassportRadioId mobileId = passport.getFromIdentifier();
mMobileIDs.add(mobileId);
getIdentifierCollection().update(mobileId);
@@ -311,8 +312,7 @@ public class PassportDecoderState extends DecoderState
}
else
{
for (PassportTalkgroup mMobileID : mMobileIDs) {
for (PassportRadioId mMobileID : mMobileIDs) {
sb.append(" ").append(mMobileID).append("\n");
}
}

View File

@@ -26,6 +26,7 @@ import io.github.dsheirer.edac.CRCPassport;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.message.MessageType;
import io.github.dsheirer.module.decode.passport.identifier.PassportRadioId;
import io.github.dsheirer.module.decode.passport.identifier.PassportTalkgroup;
import io.github.dsheirer.protocol.Protocol;
import org.apache.commons.lang3.StringUtils;
@@ -50,7 +51,7 @@ public class PassportMessage extends Message
private CorrectedBinaryMessage mMessage;
private CRC mCRC;
private PassportMessage mIdleMessage;
private PassportTalkgroup mFromIdentifier;
private PassportRadioId mFromIdentifier;
private PassportTalkgroup mToIdentifier;
private List<Identifier> mIdentifiers;
@@ -75,17 +76,17 @@ public class PassportMessage extends Message
{
if(mToIdentifier == null)
{
mToIdentifier = PassportTalkgroup.createTo(getMessage().getInt(GROUP));
mToIdentifier = PassportTalkgroup.create(getMessage().getInt(GROUP));
}
return mToIdentifier;
}
public PassportTalkgroup getFromIdentifier()
public PassportRadioId getFromIdentifier()
{
if(mFromIdentifier == null)
{
mFromIdentifier = PassportTalkgroup.createFrom(getMessage().getInt(RADIO_ID));
mFromIdentifier = PassportRadioId.create(getMessage().getInt(RADIO_ID));
}
return mFromIdentifier;

View File

@@ -0,0 +1,62 @@
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
*
*/
package io.github.dsheirer.module.decode.passport.identifier;
import io.github.dsheirer.identifier.Role;
import io.github.dsheirer.identifier.radio.RadioIdentifier;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.protocol.Protocol;
/**
* Passport Radio ID
*/
public class PassportRadioId extends RadioIdentifier implements Comparable<PassportRadioId>
{
/**
* Constructs a Passport talkgroup with a TO role.
*/
public PassportRadioId(Integer value)
{
super(value, Role.FROM);
}
@Override
public Protocol getProtocol()
{
return Protocol.PASSPORT;
}
/**
* Creates a Passport talkgroup (ie mobile id) with the value as the TO role
*/
public static PassportRadioId create(int value)
{
return new PassportRadioId(value);
}
@Override
public int compareTo(PassportRadioId o)
{
return Integer.compare(getValue(), o.getValue());
}
}

View File

@@ -34,9 +34,9 @@ public class PassportTalkgroup extends TalkgroupIdentifier implements Comparable
/**
* Constructs a Passport talkgroup with a TO role.
*/
public PassportTalkgroup(Integer value, Role role)
public PassportTalkgroup(Integer value)
{
super(value, role);
super(value, Role.TO);
}
@Override
@@ -48,17 +48,9 @@ public class PassportTalkgroup extends TalkgroupIdentifier implements Comparable
/**
* Creates a Passport talkgroup with the value as the TO role
*/
public static PassportTalkgroup createTo(int value)
public static PassportTalkgroup create(int value)
{
return new PassportTalkgroup(value, Role.TO);
}
/**
* Creates a Passport talkgroup (ie mobile id) with the value as the TO role
*/
public static PassportTalkgroup createFrom(int value)
{
return new PassportTalkgroup(value, Role.FROM);
return new PassportTalkgroup(value);
}
@Override