mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
P25 Phase 2 Decoder implementation.
This commit is contained in:
@@ -1,35 +1,40 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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-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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
import io.github.dsheirer.alias.AliasModel;
|
||||
import io.github.dsheirer.audio.IAudioPacketListener;
|
||||
import io.github.dsheirer.audio.IAudioPacketProvider;
|
||||
import io.github.dsheirer.audio.codec.mbe.MBECallSequenceRecorder;
|
||||
import io.github.dsheirer.audio.squelch.ISquelchStateListener;
|
||||
import io.github.dsheirer.audio.squelch.ISquelchStateProvider;
|
||||
import io.github.dsheirer.audio.squelch.SquelchState;
|
||||
import io.github.dsheirer.channel.state.ChannelState;
|
||||
import io.github.dsheirer.audio.squelch.SquelchStateEvent;
|
||||
import io.github.dsheirer.channel.state.AbstractChannelState;
|
||||
import io.github.dsheirer.channel.state.DecoderState;
|
||||
import io.github.dsheirer.channel.state.DecoderStateEvent;
|
||||
import io.github.dsheirer.channel.state.IDecoderStateEventListener;
|
||||
import io.github.dsheirer.channel.state.IDecoderStateEventProvider;
|
||||
import io.github.dsheirer.channel.state.MultiChannelState;
|
||||
import io.github.dsheirer.channel.state.SingleChannelState;
|
||||
import io.github.dsheirer.controller.channel.Channel;
|
||||
import io.github.dsheirer.controller.channel.ChannelEvent;
|
||||
import io.github.dsheirer.controller.channel.IChannelEventListener;
|
||||
@@ -46,6 +51,7 @@ import io.github.dsheirer.module.decode.event.IDecodeEventListener;
|
||||
import io.github.dsheirer.module.decode.event.IDecodeEventProvider;
|
||||
import io.github.dsheirer.module.decode.event.MessageActivityModel;
|
||||
import io.github.dsheirer.module.log.EventLogger;
|
||||
import io.github.dsheirer.record.binary.BinaryRecorder;
|
||||
import io.github.dsheirer.record.wave.ComplexBufferWaveRecorder;
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
@@ -108,14 +114,14 @@ public class ProcessingChain implements Listener<ChannelEvent>
|
||||
private Broadcaster<IdentifierUpdateNotification> mIdentifierUpdateNotificationBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<SourceEvent> mSourceEventBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<IMessage> mMessageBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<SquelchState> mSquelchStateBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<SquelchStateEvent> mSquelchStateEventBroadcaster = new Broadcaster<>();
|
||||
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
|
||||
protected Source mSource;
|
||||
private List<Module> mModules = new ArrayList<>();
|
||||
private DecodeEventModel mDecodeEventModel;
|
||||
private ChannelState mChannelState;
|
||||
private AbstractChannelState mChannelState;
|
||||
private MessageActivityModel mMessageActivityModel;
|
||||
|
||||
/**
|
||||
@@ -125,28 +131,39 @@ public class ProcessingChain implements Listener<ChannelEvent>
|
||||
*/
|
||||
public ProcessingChain(Channel channel, AliasModel aliasModel)
|
||||
{
|
||||
mChannelState = new ChannelState(channel, aliasModel);
|
||||
addModule(mChannelState);
|
||||
if(channel.getDecodeConfiguration().getTimeslotCount() == 1)
|
||||
{
|
||||
mChannelState = new SingleChannelState(channel, aliasModel);
|
||||
}
|
||||
else
|
||||
{
|
||||
mChannelState = new MultiChannelState(channel, aliasModel, channel.getDecodeConfiguration().getTimeslotCount());
|
||||
}
|
||||
|
||||
addModule(mChannelState);
|
||||
mDecodeEventModel = new DecodeEventModel();
|
||||
addDecodeEventListener(mDecodeEventModel);
|
||||
}
|
||||
|
||||
public AbstractChannelState getChannelState()
|
||||
{
|
||||
return mChannelState;
|
||||
}
|
||||
|
||||
public DecodeEventModel getDecodeEventModel()
|
||||
{
|
||||
return mDecodeEventModel;
|
||||
}
|
||||
|
||||
public ChannelState getChannelState()
|
||||
{
|
||||
return mChannelState;
|
||||
}
|
||||
|
||||
public MessageActivityModel getMessageActivityModel()
|
||||
{
|
||||
return mMessageActivityModel;
|
||||
}
|
||||
|
||||
|
||||
//TODO: should we introduce the concept of getTimeslot() to messages and events and then use that to vector the
|
||||
//TODO: inbound stream to the appropriate message and event models?
|
||||
|
||||
public void setMessageActivityModel(MessageActivityModel model)
|
||||
{
|
||||
mMessageActivityModel = model;
|
||||
@@ -171,7 +188,7 @@ public class ProcessingChain implements Listener<ChannelEvent>
|
||||
mBasebandComplexBufferBroadcaster.dispose();
|
||||
mDemodulatedBitstreamBufferBroadcaster.dispose();
|
||||
mMessageBroadcaster.dispose();
|
||||
mSquelchStateBroadcaster.dispose();
|
||||
mSquelchStateEventBroadcaster.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -352,7 +369,7 @@ public class ProcessingChain implements Listener<ChannelEvent>
|
||||
|
||||
if(module instanceof ISquelchStateListener)
|
||||
{
|
||||
mSquelchStateBroadcaster.addListener(((ISquelchStateListener)module).getSquelchStateListener());
|
||||
mSquelchStateEventBroadcaster.addListener(((ISquelchStateListener)module).getSquelchStateListener());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,7 +436,7 @@ public class ProcessingChain implements Listener<ChannelEvent>
|
||||
|
||||
if(module instanceof ISquelchStateListener)
|
||||
{
|
||||
mSquelchStateBroadcaster.removeListener(((ISquelchStateListener)module).getSquelchStateListener());
|
||||
mSquelchStateEventBroadcaster.removeListener(((ISquelchStateListener)module).getSquelchStateListener());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,7 +503,7 @@ public class ProcessingChain implements Listener<ChannelEvent>
|
||||
|
||||
if(module instanceof ISquelchStateProvider)
|
||||
{
|
||||
((ISquelchStateProvider)module).setSquelchStateListener(mSquelchStateBroadcaster);
|
||||
((ISquelchStateProvider)module).setSquelchStateListener(mSquelchStateEventBroadcaster);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,6 +708,14 @@ public class ProcessingChain implements Listener<ChannelEvent>
|
||||
{
|
||||
recordingModules.add(module);
|
||||
}
|
||||
else if(module instanceof MBECallSequenceRecorder)
|
||||
{
|
||||
recordingModules.add(module);
|
||||
}
|
||||
else if(module instanceof BinaryRecorder)
|
||||
{
|
||||
recordingModules.add(module);
|
||||
}
|
||||
}
|
||||
|
||||
for(Module recordingModule : recordingModules)
|
||||
@@ -806,14 +831,14 @@ public class ProcessingChain implements Listener<ChannelEvent>
|
||||
/**
|
||||
* Adds the listener to receive call events from all modules.
|
||||
*/
|
||||
public void addSquelchStateListener(Listener<SquelchState> listener)
|
||||
public void addSquelchStateListener(Listener<SquelchStateEvent> listener)
|
||||
{
|
||||
mSquelchStateBroadcaster.addListener(listener);
|
||||
mSquelchStateEventBroadcaster.addListener(listener);
|
||||
}
|
||||
|
||||
public void removeSquelchStateListener(Listener<SquelchState> listener)
|
||||
public void removeSquelchStateListener(Listener<SquelchStateEvent> listener)
|
||||
{
|
||||
mSquelchStateBroadcaster.removeListener(listener);
|
||||
mSquelchStateEventBroadcaster.removeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* 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/>
|
||||
******************************************************************************/
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * 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;
|
||||
@@ -22,11 +26,10 @@ import io.github.dsheirer.gui.editor.Editor;
|
||||
import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.JCheckBox;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class AuxDecodeConfigurationEditor extends Editor<Channel>
|
||||
@@ -34,118 +37,114 @@ 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]" ) );
|
||||
|
||||
List<DecoderType> decoders = DecoderType.getAuxDecoders();
|
||||
|
||||
Collections.sort( decoders );
|
||||
public AuxDecodeConfigurationEditor()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
for( DecoderType decoder: 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 );
|
||||
}
|
||||
}
|
||||
public AuxDecodeConfiguration getConfiguration()
|
||||
{
|
||||
return hasItem() ? getItem().getAuxDecodeConfiguration() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
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 );
|
||||
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;
|
||||
}
|
||||
}
|
||||
private void setControlsEnabled(boolean enabled)
|
||||
{
|
||||
for(AuxDecoderCheckBox box : mControls)
|
||||
{
|
||||
if(box.isEnabled() != enabled)
|
||||
{
|
||||
box.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 );
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* 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/>
|
||||
******************************************************************************/
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * 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;
|
||||
@@ -25,110 +29,111 @@ import io.github.dsheirer.gui.editor.EmptyValidatingEditor;
|
||||
import io.github.dsheirer.gui.editor.ValidatingEditor;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
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 static final long serialVersionUID = 1L;
|
||||
|
||||
private JComboBox<DecoderType> mComboDecoders;
|
||||
private ValidatingEditor<Channel> mCurrentEditor = new EmptyValidatingEditor<>( "a decoder" );
|
||||
private ValidatingEditor<Channel> mCurrentEditor = new EmptyValidatingEditor<>("a decoder");
|
||||
private ChannelMapModel mChannelMapModel;
|
||||
|
||||
public DecodeConfigurationEditor( final ChannelMapModel channelMapModel )
|
||||
{
|
||||
mChannelMapModel = channelMapModel;
|
||||
init();
|
||||
}
|
||||
public DecodeConfigurationEditor(final ChannelMapModel channelMapModel)
|
||||
{
|
||||
mChannelMapModel = channelMapModel;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "wrap 2", "[][grow,fill]", "[align top][grow,fill]" ) );
|
||||
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.getPrimaryDecoders() )
|
||||
{
|
||||
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 );
|
||||
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 )
|
||||
|
||||
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();
|
||||
}
|
||||
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 );
|
||||
if(hasItem())
|
||||
{
|
||||
mCurrentEditor.save();
|
||||
}
|
||||
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem( Channel channel )
|
||||
{
|
||||
super.setItem( channel );
|
||||
@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 );
|
||||
}
|
||||
if(hasItem())
|
||||
{
|
||||
mComboDecoders.setEnabled(true);
|
||||
mComboDecoders.setSelectedItem(channel.getDecodeConfiguration().getDecoderType());
|
||||
mCurrentEditor.setItem(channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
mComboDecoders.setEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate( Editor<Channel> editor ) throws EditorValidationException
|
||||
{
|
||||
mCurrentEditor.validate( editor );
|
||||
}
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Editor<Channel> editor) throws EditorValidationException
|
||||
{
|
||||
mCurrentEditor.validate(editor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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-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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
@@ -71,14 +73,19 @@ 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.DecodeConfigP25Phase1;
|
||||
import io.github.dsheirer.module.decode.p25.P25DecoderC4FM;
|
||||
import io.github.dsheirer.module.decode.p25.P25DecoderEditor;
|
||||
import io.github.dsheirer.module.decode.p25.P25DecoderLSM;
|
||||
import io.github.dsheirer.module.decode.p25.P25DecoderState;
|
||||
import io.github.dsheirer.module.decode.p25.P25TrafficChannelManager;
|
||||
import io.github.dsheirer.module.decode.p25.audio.P25AudioModule;
|
||||
import io.github.dsheirer.module.decode.p25.message.filter.P25MessageFilterSet;
|
||||
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;
|
||||
@@ -96,7 +103,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
public class DecoderFactory
|
||||
@@ -150,14 +156,15 @@ public class DecoderFactory
|
||||
case AM:
|
||||
modules.add(new AMDecoder(decodeConfig));
|
||||
modules.add(new AlwaysUnsquelchedDecoderState(DecoderType.AM, channel.getName()));
|
||||
AudioModule audioModuleAM = new AudioModule();
|
||||
|
||||
//Check if the user wants all audio recorded ..
|
||||
if(((DecodeConfigAM)decodeConfig).getRecordAudio())
|
||||
{
|
||||
AudioModule audioModuleAM = new AudioModule();
|
||||
audioModuleAM.setRecordAudio(true);
|
||||
modules.add(audioModuleAM);
|
||||
}
|
||||
modules.add(audioModuleAM);
|
||||
|
||||
if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER)
|
||||
{
|
||||
modules.add(new AMDemodulatorModule(AM_CHANNEL_BANDWIDTH, DEMODULATED_AUDIO_SAMPLE_RATE));
|
||||
@@ -247,10 +254,10 @@ public class DecoderFactory
|
||||
switch(p25Config.getModulation())
|
||||
{
|
||||
case C4FM:
|
||||
modules.add(new P25DecoderC4FM());
|
||||
modules.add(new P25P1DecoderC4FM());
|
||||
break;
|
||||
case CQPSK:
|
||||
modules.add(new P25DecoderLSM());
|
||||
modules.add(new P25P1DecoderLSM());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unrecognized P25 Phase 1 Modulation [" +
|
||||
@@ -261,14 +268,14 @@ public class DecoderFactory
|
||||
{
|
||||
P25TrafficChannelManager trafficChannelManager = new P25TrafficChannelManager(channel);
|
||||
modules.add(trafficChannelManager);
|
||||
modules.add(new P25DecoderState(channel, trafficChannelManager));
|
||||
modules.add(new P25P1DecoderState(channel, trafficChannelManager));
|
||||
}
|
||||
else
|
||||
{
|
||||
modules.add(new P25DecoderState(channel));
|
||||
modules.add(new P25P1DecoderState(channel));
|
||||
}
|
||||
|
||||
modules.add(new P25AudioModule(userPreferences));
|
||||
modules.add(new P25P1AudioModule(userPreferences));
|
||||
|
||||
//Add a channel rotation monitor when we have multiple control channel frequencies specified
|
||||
if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency &&
|
||||
@@ -279,6 +286,14 @@ public class DecoderFactory
|
||||
modules.add(new ChannelRotationMonitor(activeStates, userPreferences));
|
||||
}
|
||||
break;
|
||||
case P25_PHASE2:
|
||||
modules.add(new P25P2DecoderHDQPSK((DecodeConfigP25Phase2)channel.getDecodeConfiguration()));
|
||||
|
||||
modules.add(new P25P2DecoderState(channel, 0));
|
||||
modules.add(new P25P2DecoderState(channel, 1));
|
||||
modules.add(new P25P2AudioModule(userPreferences, 0));
|
||||
modules.add(new P25P2AudioModule(userPreferences, 1));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown decoder type [" + decodeConfig.getDecoderType().toString() + "]");
|
||||
}
|
||||
@@ -418,6 +433,8 @@ public class DecoderFactory
|
||||
return new DecodeConfigPassport();
|
||||
case P25_PHASE1:
|
||||
return new DecodeConfigP25Phase1();
|
||||
case P25_PHASE2:
|
||||
return new DecodeConfigP25Phase2();
|
||||
default:
|
||||
throw new IllegalArgumentException("DecodeConfigFactory - unknown decoder type [" + decoder.toString() + "]");
|
||||
}
|
||||
@@ -438,7 +455,9 @@ public class DecoderFactory
|
||||
case NBFM:
|
||||
return new NBFMDecoderEditor();
|
||||
case P25_PHASE1:
|
||||
return new P25DecoderEditor();
|
||||
return new P25P1DecoderEditor();
|
||||
case P25_PHASE2:
|
||||
return new P25P2DecoderEditor();
|
||||
case PASSPORT:
|
||||
return new PassportDecoderEditor();
|
||||
default:
|
||||
@@ -486,6 +505,15 @@ public class DecoderFactory
|
||||
copyP25.setModulation(originalP25.getModulation());
|
||||
copyP25.setTrafficChannelPoolSize(originalP25.getTrafficChannelPoolSize());
|
||||
return copyP25;
|
||||
case P25_PHASE2:
|
||||
DecodeConfigP25Phase2 originalP25P2 = (DecodeConfigP25Phase2)config;
|
||||
DecodeConfigP25Phase2 copyP25P2 = new DecodeConfigP25Phase2();
|
||||
|
||||
if(originalP25P2.getScrambleParameters() != null)
|
||||
{
|
||||
copyP25P2.setScrambleParameters(originalP25P2.getScrambleParameters().copy());
|
||||
}
|
||||
return copyP25P2;
|
||||
case PASSPORT:
|
||||
return new DecodeConfigPassport();
|
||||
default:
|
||||
@@ -495,14 +523,4 @@ public class DecoderFactory
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decoder(s) that support bitstreams indicating that they produce ReusableByteBuffers of decoded bits.
|
||||
*
|
||||
* @return set of decoders that support bitstreams.
|
||||
*/
|
||||
public static EnumSet<DecoderType> getBitstreamDecoders()
|
||||
{
|
||||
return EnumSet.of(DecoderType.P25_PHASE1, DecoderType.MPT1327);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,28 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.protocol.Protocol;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
@@ -36,7 +37,8 @@ public enum DecoderType
|
||||
MPT1327("MPT1327", "MPT1327", Protocol.MPT1327),
|
||||
NBFM("NBFM", "NBFM", Protocol.UNKNOWN),
|
||||
PASSPORT("Passport", "Passport", Protocol.PASSPORT),
|
||||
P25_PHASE1("P25 Phase I", "P25-1", Protocol.APCO25),
|
||||
P25_PHASE1("P25 Phase 1", "P25-1", Protocol.APCO25),
|
||||
P25_PHASE2("P25 Phase 2", "P25-2", Protocol.APCO25),
|
||||
|
||||
//Auxiliary Decoders
|
||||
FLEETSYNC2("Fleetsync II", "Fleetsync2", Protocol.FLEETSYNC),
|
||||
@@ -56,33 +58,41 @@ public enum DecoderType
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary decoders
|
||||
* Primary decoders that operate on I/Q sample streams
|
||||
*/
|
||||
public static EnumSet<DecoderType> getPrimaryDecoders()
|
||||
{
|
||||
return EnumSet.of(DecoderType.AM,
|
||||
DecoderType.LTR_NET,
|
||||
DecoderType.LTR_STANDARD,
|
||||
DecoderType.MPT1327,
|
||||
DecoderType.NBFM,
|
||||
DecoderType.P25_PHASE1,
|
||||
DecoderType.PASSPORT);
|
||||
}
|
||||
public static EnumSet<DecoderType> PRIMARY_DECODERS =
|
||||
EnumSet.of(DecoderType.AM,
|
||||
DecoderType.LTR_NET,
|
||||
DecoderType.LTR_STANDARD,
|
||||
DecoderType.MPT1327,
|
||||
DecoderType.NBFM,
|
||||
DecoderType.P25_PHASE1,
|
||||
DecoderType.P25_PHASE2,
|
||||
DecoderType.PASSPORT);
|
||||
|
||||
/**
|
||||
* Available auxiliary decoders.
|
||||
* Auxiliary decoders that operate on in-band signalling in the decoded audio channel
|
||||
*/
|
||||
public static ArrayList<DecoderType> getAuxDecoders()
|
||||
{
|
||||
ArrayList<DecoderType> decoders = new ArrayList<DecoderType>();
|
||||
public static final EnumSet<DecoderType> AUX_DECODERS =
|
||||
EnumSet.of(DecoderType.FLEETSYNC2,
|
||||
DecoderType.LJ_1200,
|
||||
DecoderType.MDC1200,
|
||||
DecoderType.TAIT_1200);
|
||||
|
||||
decoders.add(DecoderType.FLEETSYNC2);
|
||||
decoders.add(DecoderType.LJ_1200);
|
||||
decoders.add(DecoderType.MDC1200);
|
||||
decoders.add(DecoderType.TAIT_1200);
|
||||
/**
|
||||
* Decoders that produce a (recordable) bitstream
|
||||
*/
|
||||
public static final EnumSet<DecoderType> BITSTREAM_DECODERS =
|
||||
EnumSet.of(DecoderType.MPT1327,
|
||||
DecoderType.P25_PHASE1,
|
||||
DecoderType.P25_PHASE2);
|
||||
|
||||
return decoders;
|
||||
}
|
||||
/**
|
||||
* Decoders that produce (recordable) MBE audio codec frames
|
||||
*/
|
||||
public static final EnumSet<DecoderType> MBE_AUDIO_CODEC_DECODERS =
|
||||
EnumSet.of(DecoderType.P25_PHASE1,
|
||||
DecoderType.P25_PHASE2);
|
||||
|
||||
public Protocol getProtocol()
|
||||
{
|
||||
@@ -104,4 +114,20 @@ public enum DecoderType
|
||||
{
|
||||
return mDisplayString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the decoder type produces a (recordable) bitstream
|
||||
*/
|
||||
public boolean providesBitstream()
|
||||
{
|
||||
return BITSTREAM_DECODERS.contains(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the decoder type produces (recordable) MBE audio codec frames
|
||||
*/
|
||||
public boolean providesMBEAudioFrames()
|
||||
{
|
||||
return MBE_AUDIO_CODEC_DECODERS.contains(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,76 +1,80 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2015 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-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.audio.squelch.ISquelchStateProvider;
|
||||
import io.github.dsheirer.audio.squelch.SquelchState;
|
||||
import io.github.dsheirer.audio.squelch.SquelchStateEvent;
|
||||
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
|
||||
/**
|
||||
* Primary decoder adds the following functionality over the basic decoder:
|
||||
*
|
||||
*
|
||||
* - Provides audio squelch control
|
||||
*/
|
||||
|
||||
public abstract class PrimaryDecoder extends Decoder implements ISquelchStateProvider
|
||||
{
|
||||
protected Listener<SquelchState> mSquelchStateListener;
|
||||
|
||||
protected DecodeConfiguration mDecodeConfiguration;
|
||||
|
||||
public PrimaryDecoder( DecodeConfiguration config )
|
||||
{
|
||||
mDecodeConfiguration = config;
|
||||
}
|
||||
|
||||
public DecodeConfiguration getDecodeConfiguration()
|
||||
{
|
||||
return mDecodeConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
super.dispose();
|
||||
|
||||
mSquelchStateListener = null;
|
||||
mDecodeConfiguration = null;
|
||||
}
|
||||
protected Listener<SquelchStateEvent> mSquelchStateListener;
|
||||
|
||||
public void broadcast( SquelchState state )
|
||||
{
|
||||
if( mSquelchStateListener != null )
|
||||
{
|
||||
mSquelchStateListener.receive( state );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSquelchStateListener( Listener<SquelchState> listener )
|
||||
{
|
||||
mSquelchStateListener = listener;
|
||||
}
|
||||
protected DecodeConfiguration mDecodeConfiguration;
|
||||
|
||||
@Override
|
||||
public void removeSquelchStateListener()
|
||||
{
|
||||
mSquelchStateListener = null;
|
||||
}
|
||||
public PrimaryDecoder(DecodeConfiguration config)
|
||||
{
|
||||
mDecodeConfiguration = config;
|
||||
}
|
||||
|
||||
public DecodeConfiguration getDecodeConfiguration()
|
||||
{
|
||||
return mDecodeConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
super.dispose();
|
||||
|
||||
mSquelchStateListener = null;
|
||||
mDecodeConfiguration = null;
|
||||
}
|
||||
|
||||
public void broadcast(SquelchStateEvent state)
|
||||
{
|
||||
if(mSquelchStateListener != null)
|
||||
{
|
||||
mSquelchStateListener.receive(state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSquelchStateListener(Listener<SquelchStateEvent> listener)
|
||||
{
|
||||
mSquelchStateListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSquelchStateListener()
|
||||
{
|
||||
mSquelchStateListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.JsonIgnore;
|
||||
@@ -27,7 +33,8 @@ import io.github.dsheirer.module.decode.ltrnet.DecodeConfigLTRNet;
|
||||
import io.github.dsheirer.module.decode.ltrstandard.DecodeConfigLTRStandard;
|
||||
import io.github.dsheirer.module.decode.mpt1327.DecodeConfigMPT1327;
|
||||
import io.github.dsheirer.module.decode.nbfm.DecodeConfigNBFM;
|
||||
import io.github.dsheirer.module.decode.p25.DecodeConfigP25Phase1;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.DecodeConfigP25Phase1;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.DecodeConfigP25Phase2;
|
||||
import io.github.dsheirer.module.decode.passport.DecodeConfigPassport;
|
||||
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
|
||||
|
||||
@@ -40,12 +47,13 @@ import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
|
||||
@JsonSubTypes.Type(value = DecodeConfigMPT1327.class, name = "decodeConfigMPT1327"),
|
||||
@JsonSubTypes.Type(value = DecodeConfigNBFM.class, name = "decodeConfigNBFM"),
|
||||
@JsonSubTypes.Type(value = DecodeConfigP25Phase1.class, name = "decodeConfigP25Phase1"),
|
||||
@JsonSubTypes.Type(value = DecodeConfigP25Phase2.class, name = "decodeConfigP25Phase2"),
|
||||
@JsonSubTypes.Type(value = DecodeConfigPassport.class, name = "decodeConfigPassport")
|
||||
})
|
||||
@JacksonXmlRootElement(localName = "decode_configuration")
|
||||
public abstract class DecodeConfiguration extends Configuration
|
||||
{
|
||||
public static final int DEFAULT_CALL_TIMEOUT_SECONDS = 45;
|
||||
public static final int DEFAULT_CALL_TIMEOUT_DELAY_SECONDS = 45;
|
||||
public static final int CALL_TIMEOUT_MINIMUM = 1;
|
||||
public static final int CALL_TIMEOUT_MAXIMUM = 300; //5 minutes
|
||||
|
||||
@@ -62,4 +70,10 @@ public abstract class DecodeConfiguration extends Configuration
|
||||
|
||||
@JsonIgnore
|
||||
public abstract ChannelSpecification getChannelSpecification();
|
||||
|
||||
@JsonIgnore
|
||||
public int getTimeslotCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.event;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import io.github.dsheirer.channel.IChannelDescriptor;
|
||||
import io.github.dsheirer.identifier.IdentifierCollection;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
@@ -37,6 +40,7 @@ public class DecodeEvent implements IDecodeEvent
|
||||
private IChannelDescriptor mChannelDescriptor;
|
||||
private String mDetails;
|
||||
private Protocol mProtocol;
|
||||
private Integer mTimeslot;
|
||||
|
||||
public DecodeEvent(long start)
|
||||
{
|
||||
@@ -187,6 +191,49 @@ public class DecodeEvent implements IDecodeEvent
|
||||
mProtocol = protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timeslot for this event
|
||||
* @return timeslot or default value of 0
|
||||
*/
|
||||
@Override
|
||||
public Integer getTimeslot()
|
||||
{
|
||||
return mTimeslot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this event specifies a timeslot
|
||||
*/
|
||||
public boolean hasTimeslot()
|
||||
{
|
||||
return mTimeslot != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timeslot for this event
|
||||
* @param timeslot of the event
|
||||
*/
|
||||
public void setTimeslot(Integer timeslot)
|
||||
{
|
||||
mTimeslot = timeslot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(mProtocol);
|
||||
sb.append(" DECODE EVENT: ").append(getEventDescription());
|
||||
sb.append(" DETAILS:").append(getDetails());
|
||||
if(mIdentifierCollection != null)
|
||||
{
|
||||
sb.append(" IDS:").append(Joiner.on(",").join(mIdentifierCollection.getIdentifiers()));
|
||||
}
|
||||
sb.append(" DURATION:").append(mDuration);
|
||||
sb.append(" CHANNEL:").append(mChannelDescriptor);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder pattern for constructing decode events.
|
||||
*/
|
||||
@@ -199,6 +246,7 @@ public class DecodeEvent implements IDecodeEvent
|
||||
protected IChannelDescriptor mChannelDescriptor;
|
||||
protected String mDetails;
|
||||
protected Protocol mProtocol = Protocol.UNKNOWN;
|
||||
protected Integer mTimeslot;
|
||||
|
||||
/**
|
||||
* Constructs a builder instance with the specified start time in milliseconds
|
||||
@@ -279,6 +327,12 @@ public class DecodeEvent implements IDecodeEvent
|
||||
return this;
|
||||
}
|
||||
|
||||
public DecodeEventBuilder timeslot(Integer timeslot)
|
||||
{
|
||||
mTimeslot = timeslot;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the decode event
|
||||
*/
|
||||
@@ -291,6 +345,7 @@ public class DecodeEvent implements IDecodeEvent
|
||||
decodeEvent.setEventDescription(mEventDescription);
|
||||
decodeEvent.setIdentifierCollection(mIdentifierCollection);
|
||||
decodeEvent.setProtocol(mProtocol);
|
||||
decodeEvent.setTimeslot(mTimeslot);
|
||||
return decodeEvent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014,2015 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-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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.event;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
@@ -184,7 +188,30 @@ public class DecodeEventModel extends AbstractTableModel implements Listener<IDe
|
||||
case COLUMN_TO_ALIAS:
|
||||
return event.getIdentifierCollection();
|
||||
case COLUMN_CHANNEL:
|
||||
return event.getChannelDescriptor();
|
||||
IChannelDescriptor channelDescriptor = event.getChannelDescriptor();
|
||||
|
||||
if(channelDescriptor != null)
|
||||
{
|
||||
if(event.hasTimeslot())
|
||||
{
|
||||
return channelDescriptor.toString() + " TS:" + event.getTimeslot();
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelDescriptor.toString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(event.hasTimeslot())
|
||||
{
|
||||
return "TS:" + event.getTimeslot();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
case COLUMN_FREQUENCY:
|
||||
return event.getChannelDescriptor();
|
||||
case COLUMN_DETAILS:
|
||||
@@ -214,7 +241,7 @@ public class DecodeEventModel extends AbstractTableModel implements Listener<IDe
|
||||
case COLUMN_TO_ID:
|
||||
return IdentifierCollection.class;
|
||||
case COLUMN_CHANNEL:
|
||||
return IChannelDescriptor.class;
|
||||
return String.class;
|
||||
}
|
||||
|
||||
return super.getColumnClass(columnIndex);
|
||||
|
||||
@@ -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-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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.event;
|
||||
|
||||
@@ -106,7 +108,6 @@ public class DecodeEventPanel extends JPanel implements Listener<ProcessingChain
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void updateCellRenderers()
|
||||
{
|
||||
mTable.getColumnModel().getColumn(DecodeEventModel.COLUMN_TIME)
|
||||
@@ -356,7 +357,7 @@ public class DecodeEventPanel extends JPanel implements Listener<ProcessingChain
|
||||
*/
|
||||
public class FrequencyCellRenderer extends DefaultTableCellRenderer
|
||||
{
|
||||
private DecimalFormat mFrequencyFormatter = new DecimalFormat("0.00000 MHz");
|
||||
private DecimalFormat mFrequencyFormatter = new DecimalFormat("0.00000");
|
||||
|
||||
public FrequencyCellRenderer()
|
||||
{
|
||||
@@ -397,22 +398,5 @@ public class DecodeEventPanel extends JPanel implements Listener<ProcessingChain
|
||||
{
|
||||
setHorizontalAlignment(JLabel.CENTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
|
||||
{
|
||||
JLabel label = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||
|
||||
if(value instanceof IChannelDescriptor)
|
||||
{
|
||||
label.setText(value.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
label.setText(null);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.event;
|
||||
@@ -71,4 +73,15 @@ public interface IDecodeEvent
|
||||
* Protocol for the decoder that produced the event
|
||||
*/
|
||||
Protocol getProtocol();
|
||||
|
||||
/**
|
||||
* Timeslot for the event.
|
||||
* @return timeslot or default of 0
|
||||
*/
|
||||
Integer getTimeslot();
|
||||
|
||||
/**
|
||||
* Indicates if the event has a timeslot specified
|
||||
*/
|
||||
boolean hasTimeslot();
|
||||
}
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.event;
|
||||
|
||||
import io.github.dsheirer.filter.FilterSet;
|
||||
@@ -31,12 +35,13 @@ public class MessageActivityModel extends AbstractTableModel implements Listener
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final int TIME = 0;
|
||||
private static final int PROTOCOL = 1;
|
||||
private static final int MESSAGE = 2;
|
||||
private static final int TIMESLOT = 2;
|
||||
private static final int MESSAGE = 3;
|
||||
|
||||
protected int mMaxMessages = 500;
|
||||
protected LinkedList<MessageItem> mMessageItems = new LinkedList<>();
|
||||
protected int[] mColumnWidths = {20, 20, 500};
|
||||
protected String[] mHeaders = new String[]{"Time", "Protocol", "Message"};
|
||||
protected String[] mHeaders = new String[]{"Time", "Protocol", "Timeslot", "Message"};
|
||||
|
||||
private SimpleDateFormat mSDFTime = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
|
||||
|
||||
@@ -168,6 +173,8 @@ public class MessageActivityModel extends AbstractTableModel implements Listener
|
||||
return messageItem.getTimestamp(mSDFTime);
|
||||
case PROTOCOL:
|
||||
return messageItem.getProtocol();
|
||||
case TIMESLOT:
|
||||
return messageItem.getTimeslot();
|
||||
case MESSAGE:
|
||||
return messageItem.getText();
|
||||
default:
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.event;
|
||||
@@ -67,6 +69,11 @@ public class MessageItem
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
public int getTimeslot()
|
||||
{
|
||||
return mMessage.getTimeslot();
|
||||
}
|
||||
|
||||
public String getText()
|
||||
{
|
||||
if(mText == null)
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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-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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.fleetsync2;
|
||||
|
||||
import io.github.dsheirer.channel.state.DecoderState;
|
||||
@@ -56,6 +59,7 @@ public class Fleetsync2DecoderState extends DecoderState
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
mIdents.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -25,7 +25,7 @@ import io.github.dsheirer.module.decode.ip.ars.ARSPacket;
|
||||
import io.github.dsheirer.module.decode.ip.ipv4.IPV4Header;
|
||||
import io.github.dsheirer.module.decode.ip.ipv4.IPV4Packet;
|
||||
import io.github.dsheirer.module.decode.ip.udp.UDPPacket;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp.SNDCPPacketHeader;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPPacketHeader;
|
||||
import io.github.dsheirer.module.decode.p25.reference.IPHeaderCompression;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -21,7 +21,7 @@
|
||||
package io.github.dsheirer.module.decode.ip;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp.SNDCPPacketHeader;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPPacketHeader;
|
||||
|
||||
public class UnknownCompressedHeaderPacket implements IPacket
|
||||
{
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.lj1200;
|
||||
|
||||
@@ -144,6 +146,7 @@ public class LJ1200DecoderState extends DecoderState
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
mAddresses.clear();
|
||||
resetState();
|
||||
}
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
@@ -113,6 +115,7 @@ public class LTRNetDecoderState extends DecoderState
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
mChannelMapHigh = null;
|
||||
mChannelMapLow = null;
|
||||
mChannelMap.clear();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -21,7 +21,7 @@
|
||||
package io.github.dsheirer.module.decode.ltrnet.channel;
|
||||
|
||||
import io.github.dsheirer.channel.IChannelDescriptor;
|
||||
import io.github.dsheirer.module.decode.p25.message.IFrequencyBand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
public class LtrNetChannel implements IChannelDescriptor, Comparable<LtrNetChannel>
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
@@ -147,6 +149,7 @@ public class LTRStandardDecoderState extends DecoderState
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
mActiveCalls.clear();
|
||||
mTalkgroupsFirstHeard.clear();
|
||||
mTalkgroups.clear();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -21,7 +21,7 @@
|
||||
package io.github.dsheirer.module.decode.ltrstandard.channel;
|
||||
|
||||
import io.github.dsheirer.channel.IChannelDescriptor;
|
||||
import io.github.dsheirer.module.decode.p25.message.IFrequencyBand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
public class LtrChannel implements IChannelDescriptor, Comparable<LtrChannel>
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.mdc1200;
|
||||
|
||||
@@ -52,6 +54,7 @@ public class MDCDecoderState extends DecoderState
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
mIdents.clear();
|
||||
mEmergencyIdents.clear();
|
||||
|
||||
|
||||
@@ -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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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 com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
@@ -28,7 +32,7 @@ public class DecodeConfigMPT1327 extends DecodeConfiguration
|
||||
private String mChannelMapName;
|
||||
private Sync mSync = Sync.NORMAL;
|
||||
|
||||
private int mCallTimeout = DEFAULT_CALL_TIMEOUT_SECONDS;
|
||||
private int mCallTimeout = DEFAULT_CALL_TIMEOUT_DELAY_SECONDS;
|
||||
private int mTrafficChannelPoolSize = TRAFFIC_CHANNEL_LIMIT_DEFAULT;
|
||||
|
||||
public DecodeConfigMPT1327()
|
||||
@@ -82,7 +86,7 @@ public class DecodeConfigMPT1327 extends DecodeConfiguration
|
||||
}
|
||||
else
|
||||
{
|
||||
mCallTimeout = DEFAULT_CALL_TIMEOUT_SECONDS;
|
||||
mCallTimeout = DEFAULT_CALL_TIMEOUT_DELAY_SECONDS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 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-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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
@@ -114,7 +117,7 @@ public class MPT1327DecoderEditor extends ValidatingEditor<Channel>
|
||||
add(mTrafficChannelPoolSize);
|
||||
|
||||
mCallTimeout = new JSlider(JSlider.HORIZONTAL, DecodeConfiguration.CALL_TIMEOUT_MINIMUM,
|
||||
DecodeConfiguration.CALL_TIMEOUT_MAXIMUM, DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS);
|
||||
DecodeConfiguration.CALL_TIMEOUT_MAXIMUM, DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS);
|
||||
mCallTimeout.setEnabled(false);
|
||||
mCallTimeout.setMajorTickSpacing(100);
|
||||
mCallTimeout.setMinorTickSpacing(50);
|
||||
@@ -211,7 +214,7 @@ public class MPT1327DecoderEditor extends ValidatingEditor<Channel>
|
||||
else
|
||||
{
|
||||
mTrafficChannelPoolSize.setValue(DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT);
|
||||
mCallTimeout.setValue(DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS);
|
||||
mCallTimeout.setValue(DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS);
|
||||
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@@ -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-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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
@@ -270,8 +272,8 @@ public class MPT1327DecoderState extends DecoderState
|
||||
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
mIdents.clear();
|
||||
|
||||
resetState();
|
||||
}
|
||||
|
||||
@@ -306,7 +308,7 @@ public class MPT1327DecoderState extends DecoderState
|
||||
if(mChannelType == ChannelType.STANDARD)
|
||||
{
|
||||
broadcast(new ChangeChannelTimeoutEvent(this, mChannelType,
|
||||
DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS * 1000));
|
||||
DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS * 1000));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
@@ -1075,105 +1077,65 @@ public class MPT1327Message extends Message
|
||||
case HEAD_PLUS1:
|
||||
if(format == SDMFormat.MPT1327)
|
||||
{
|
||||
sb.append(mMessage.getHex(B2_SDM_STF0_START,
|
||||
B2_SDM_STF0_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B2_SDM_STF0_START, B2_SDM_STF0_END));
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(mMessage.getHex(B2_SDM_STF1_START,
|
||||
B2_SDM_STF1_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B2_SDM_STF1_START, B2_SDM_STF1_END));
|
||||
}
|
||||
break;
|
||||
case HEAD_PLUS2:
|
||||
if(format == SDMFormat.MPT1327)
|
||||
{
|
||||
sb.append(mMessage.getHex(B2_SDM_STF0_START,
|
||||
B2_SDM_STF0_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B2_SDM_STF0_START, B2_SDM_STF0_END));
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.getHex(B3_SDM_START,
|
||||
B3_SDM_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B3_SDM_START, B3_SDM_END));
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(mMessage.getHex(B2_SDM_STF1_START,
|
||||
B2_SDM_STF1_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B2_SDM_STF1_START, B2_SDM_STF1_END));
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.getHex(B3_SDM_START,
|
||||
B3_SDM_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B3_SDM_START, B3_SDM_END));
|
||||
}
|
||||
break;
|
||||
case HEAD_PLUS3:
|
||||
if(format == SDMFormat.MPT1327)
|
||||
{
|
||||
sb.append(mMessage.getHex(B2_SDM_STF0_START,
|
||||
B2_SDM_STF0_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B2_SDM_STF0_START, B2_SDM_STF0_END));
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.getHex(B3_SDM_START,
|
||||
B3_SDM_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B3_SDM_START, B3_SDM_END));
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.getHex(B4_SDM_STF0_START,
|
||||
B4_SDM_STF0_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B4_SDM_STF0_START, B4_SDM_STF0_END));
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(mMessage.getHex(B2_SDM_STF1_START,
|
||||
B2_SDM_STF1_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B2_SDM_STF1_START, B2_SDM_STF1_END));
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.getHex(B3_SDM_START,
|
||||
B3_SDM_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B3_SDM_START, B3_SDM_END));
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.getHex(B4_SDM_STF1_START,
|
||||
B4_SDM_STF1_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B4_SDM_STF1_START, B4_SDM_STF1_END));
|
||||
}
|
||||
break;
|
||||
case HEAD_PLUS4:
|
||||
if(format == SDMFormat.MPT1327)
|
||||
{
|
||||
sb.append(mMessage.getHex(B2_SDM_STF0_START,
|
||||
B2_SDM_STF0_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B2_SDM_STF0_START, B2_SDM_STF0_END));
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.getHex(B3_SDM_START,
|
||||
B3_SDM_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B3_SDM_START, B3_SDM_END));
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.getHex(B4_SDM_STF0_START,
|
||||
B4_SDM_STF0_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B4_SDM_STF0_START, B4_SDM_STF0_END));
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.getHex(B5_SDM_START,
|
||||
B5_SDM_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B5_SDM_START, B5_SDM_END));
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(mMessage.getHex(B2_SDM_STF1_START,
|
||||
B2_SDM_STF1_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B2_SDM_STF1_START, B2_SDM_STF1_END));
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.getHex(B3_SDM_START,
|
||||
B3_SDM_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B3_SDM_START, B3_SDM_END));
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.getHex(B4_SDM_STF1_START,
|
||||
B4_SDM_STF1_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B4_SDM_STF1_START, B4_SDM_STF1_END));
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.getHex(B5_SDM_START,
|
||||
B5_SDM_END,
|
||||
12));
|
||||
sb.append(mMessage.getHex(B5_SDM_START, B5_SDM_END));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -22,7 +22,7 @@ package io.github.dsheirer.module.decode.mpt1327.channel;
|
||||
|
||||
import io.github.dsheirer.channel.IChannelDescriptor;
|
||||
import io.github.dsheirer.controller.channel.map.ChannelMap;
|
||||
import io.github.dsheirer.module.decode.p25.message.IFrequencyBand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
|
||||
public interface C4FMFrameListener
|
||||
{
|
||||
/**
|
||||
* Listener interface to receive the output of the C4FMMessageFramer.
|
||||
*
|
||||
* @param buffer - framed message without the sync pattern
|
||||
* @param inverted - flag indicating if the message was received inverted
|
||||
*/
|
||||
public void receive( BinaryMessage buffer, boolean inverted );
|
||||
|
||||
}
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
@@ -28,15 +30,29 @@ import io.github.dsheirer.controller.channel.IChannelEventListener;
|
||||
import io.github.dsheirer.controller.channel.IChannelEventProvider;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.IdentifierCollection;
|
||||
import io.github.dsheirer.identifier.MutableIdentifierCollection;
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.scramble.ScrambleParameterIdentifier;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.message.IMessageListener;
|
||||
import io.github.dsheirer.module.Module;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
|
||||
import io.github.dsheirer.module.decode.event.DecodeEvent;
|
||||
import io.github.dsheirer.module.decode.event.DecodeEventType;
|
||||
import io.github.dsheirer.module.decode.event.IDecodeEvent;
|
||||
import io.github.dsheirer.module.decode.event.IDecodeEventProvider;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.channel.P25Channel;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.channel.P25P2Channel;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.channel.P25P2ExplicitChannel;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.DecodeConfigP25Phase1;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCNetworkStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.NetworkStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.DecodeConfigP25Phase2;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters;
|
||||
import io.github.dsheirer.module.decode.p25.reference.ServiceOptions;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.source.config.SourceConfigTuner;
|
||||
@@ -70,14 +86,17 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
* This manager monitors channel events watching for events related to managed traffic channels.
|
||||
*/
|
||||
public class P25TrafficChannelManager extends Module implements IDecodeEventProvider, IChannelEventListener,
|
||||
IChannelEventProvider
|
||||
IChannelEventProvider, IMessageListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25TrafficChannelManager.class);
|
||||
public static final String CHANNEL_START_REJECTED = "CHANNEL START REJECTED";
|
||||
public static final String MAX_TRAFFIC_CHANNELS_EXCEEDED = "MAX TRAFFIC CHANNELS EXCEEDED";
|
||||
|
||||
private Queue<Channel> mAvailableTrafficChannelQueue = new ConcurrentLinkedQueue<>();
|
||||
private List<Channel> mManagedTrafficChannels;
|
||||
private Queue<Channel> mAvailablePhase1TrafficChannelQueue = new ConcurrentLinkedQueue<>();
|
||||
private List<Channel> mManagedPhase1TrafficChannels;
|
||||
private Queue<Channel> mAvailablePhase2TrafficChannelQueue = new ConcurrentLinkedQueue<>();
|
||||
private List<Channel> mManagedPhase2TrafficChannels;
|
||||
|
||||
private Map<APCO25Channel,Channel> mAllocatedTrafficChannelMap = new ConcurrentHashMap<>();
|
||||
private Map<APCO25Channel,P25ChannelGrantEvent> mChannelGrantEventMap = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -85,8 +104,11 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
|
||||
private Listener<IDecodeEvent> mDecodeEventListener;
|
||||
|
||||
private TrafficChannelTeardownMonitor mTrafficChannelTeardownMonitor = new TrafficChannelTeardownMonitor();
|
||||
private Channel mParentChannel;
|
||||
private ScrambleParameters mPhase2ScrambleParameters;
|
||||
private Listener<IMessage> mMessageListener;
|
||||
|
||||
private boolean mIgnoreDataCalls = false;
|
||||
private boolean mIgnoreDataCalls;
|
||||
|
||||
/**
|
||||
* Monitors call events and allocates traffic decoder channels in response
|
||||
@@ -97,42 +119,93 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
|
||||
*/
|
||||
public P25TrafficChannelManager(Channel parentChannel)
|
||||
{
|
||||
createTrafficChannels(parentChannel);
|
||||
DecodeConfigP25Phase1 p25Config = (DecodeConfigP25Phase1)parentChannel.getDecodeConfiguration();
|
||||
mIgnoreDataCalls = p25Config.getIgnoreDataCalls();
|
||||
mParentChannel = parentChannel;
|
||||
|
||||
if(parentChannel.getDecodeConfiguration() instanceof DecodeConfigP25Phase1)
|
||||
{
|
||||
mIgnoreDataCalls = ((DecodeConfigP25Phase1)parentChannel.getDecodeConfiguration()).getIgnoreDataCalls();
|
||||
}
|
||||
|
||||
createPhase1TrafficChannels();
|
||||
createPhase2TrafficChannels();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates up to the maximum number of traffic channels for use in allocating traffic channels.
|
||||
*
|
||||
* @param parentChannel for inheriting naming, alias list and traffic channel pool size properties
|
||||
* Note: this method uses lazy initialization and will only create the channels once. Subsequent calls will be ignored.
|
||||
*/
|
||||
private void createTrafficChannels(Channel parentChannel)
|
||||
private void createPhase1TrafficChannels()
|
||||
{
|
||||
DecodeConfiguration decodeConfiguration = parentChannel.getDecodeConfiguration();
|
||||
List<Channel> trafficChannelList = new ArrayList<>();
|
||||
|
||||
if(decodeConfiguration instanceof DecodeConfigP25Phase1)
|
||||
if(mManagedPhase1TrafficChannels == null)
|
||||
{
|
||||
DecodeConfigP25Phase1 p25DecodeConfig = (DecodeConfigP25Phase1)decodeConfiguration;
|
||||
DecodeConfiguration decodeConfiguration = mParentChannel.getDecodeConfiguration();
|
||||
List<Channel> trafficChannelList = new ArrayList<>();
|
||||
|
||||
int maxTrafficChannels = p25DecodeConfig.getTrafficChannelPoolSize();
|
||||
|
||||
for(int x = 0; x < maxTrafficChannels; x++)
|
||||
if(decodeConfiguration instanceof DecodeConfigP25Phase1)
|
||||
{
|
||||
Channel trafficChannel = new Channel("TRAFFIC", ChannelType.TRAFFIC);
|
||||
trafficChannel.setAliasListName(parentChannel.getAliasListName());
|
||||
trafficChannel.setSystem(parentChannel.getSystem());
|
||||
trafficChannel.setSite(parentChannel.getSite());
|
||||
trafficChannel.setDecodeConfiguration(p25DecodeConfig);
|
||||
trafficChannel.setEventLogConfiguration(parentChannel.getEventLogConfiguration());
|
||||
trafficChannel.setRecordConfiguration(parentChannel.getRecordConfiguration());
|
||||
trafficChannelList.add(trafficChannel);
|
||||
}
|
||||
}
|
||||
DecodeConfigP25Phase1 p25DecodeConfig = (DecodeConfigP25Phase1)decodeConfiguration;
|
||||
|
||||
mAvailableTrafficChannelQueue.addAll(trafficChannelList);
|
||||
mManagedTrafficChannels = Collections.unmodifiableList(trafficChannelList);
|
||||
int maxTrafficChannels = p25DecodeConfig.getTrafficChannelPoolSize();
|
||||
|
||||
if(maxTrafficChannels > 0)
|
||||
{
|
||||
for(int x = 0; x < maxTrafficChannels; x++)
|
||||
{
|
||||
Channel trafficChannel = new Channel("TRAFFIC", ChannelType.TRAFFIC);
|
||||
trafficChannel.setAliasListName(mParentChannel.getAliasListName());
|
||||
trafficChannel.setSystem(mParentChannel.getSystem());
|
||||
trafficChannel.setSite(mParentChannel.getSite());
|
||||
trafficChannel.setDecodeConfiguration(p25DecodeConfig);
|
||||
trafficChannel.setEventLogConfiguration(mParentChannel.getEventLogConfiguration());
|
||||
trafficChannel.setRecordConfiguration(mParentChannel.getRecordConfiguration());
|
||||
trafficChannelList.add(trafficChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mAvailablePhase1TrafficChannelQueue.addAll(trafficChannelList);
|
||||
mManagedPhase1TrafficChannels = Collections.unmodifiableList(trafficChannelList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates up to the maximum number of traffic channels for use in allocating traffic channels.
|
||||
*
|
||||
* Note: this method uses lazy initialization and will only create the channels once. Subsequent calls will be ignored.
|
||||
*/
|
||||
private void createPhase2TrafficChannels()
|
||||
{
|
||||
if(mManagedPhase2TrafficChannels == null)
|
||||
{
|
||||
DecodeConfiguration decodeConfiguration = mParentChannel.getDecodeConfiguration();
|
||||
List<Channel> trafficChannelList = new ArrayList<>();
|
||||
|
||||
if(decodeConfiguration instanceof DecodeConfigP25Phase1)
|
||||
{
|
||||
DecodeConfigP25Phase1 p25DecodeConfig = (DecodeConfigP25Phase1)decodeConfiguration;
|
||||
|
||||
int maxTrafficChannels = p25DecodeConfig.getTrafficChannelPoolSize();
|
||||
|
||||
if(maxTrafficChannels > 0)
|
||||
{
|
||||
for(int x = 0; x < maxTrafficChannels; x++)
|
||||
{
|
||||
Channel trafficChannel = new Channel("TRAFFIC", ChannelType.TRAFFIC);
|
||||
trafficChannel.setAliasListName(mParentChannel.getAliasListName());
|
||||
trafficChannel.setSystem(mParentChannel.getSystem());
|
||||
trafficChannel.setSite(mParentChannel.getSite());
|
||||
trafficChannel.setDecodeConfiguration(new DecodeConfigP25Phase2());
|
||||
trafficChannel.setEventLogConfiguration(mParentChannel.getEventLogConfiguration());
|
||||
trafficChannel.setRecordConfiguration(mParentChannel.getRecordConfiguration());
|
||||
trafficChannelList.add(trafficChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mAvailablePhase2TrafficChannelQueue.addAll(trafficChannelList);
|
||||
mManagedPhase2TrafficChannels = Collections.unmodifiableList(trafficChannelList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,6 +231,46 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
|
||||
public void processChannelGrant(APCO25Channel apco25Channel, ServiceOptions serviceOptions,
|
||||
IdentifierCollection identifierCollection, Opcode opcode, long timestamp)
|
||||
{
|
||||
if(apco25Channel.isTDMAChannel())
|
||||
{
|
||||
if(apco25Channel.getTimeslotCount() == 2)
|
||||
{
|
||||
//Data channels may be granted as a phase 2 channel grant but are still phase 1 channels
|
||||
if(opcode.isDataChannelGrant())
|
||||
{
|
||||
APCO25Channel phase1Channel = convertPhase2ToPhase1(apco25Channel);
|
||||
processPhase1ChannelGrant(phase1Channel, serviceOptions, identifierCollection, opcode, timestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
processPhase2ChannelGrant(apco25Channel, serviceOptions, identifierCollection, opcode, timestamp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Cannot process TDMA channel grant - unrecognized timeslot count: " +
|
||||
apco25Channel.getTimeslotCount());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
processPhase1ChannelGrant(apco25Channel, serviceOptions, identifierCollection, opcode, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes Phase 1 channel grants to allocate traffic channels and track overall channel usage. Generates
|
||||
* decode events for each new channel that is allocated.
|
||||
*
|
||||
* @param apco25Channel for the traffic channel
|
||||
* @param serviceOptions for the traffic channel - optional can be null
|
||||
* @param identifierCollection associated with the channel grant
|
||||
* @param opcode to identify the call type for the event description
|
||||
*/
|
||||
private void processPhase1ChannelGrant(APCO25Channel apco25Channel, ServiceOptions serviceOptions,
|
||||
IdentifierCollection identifierCollection, Opcode opcode, long timestamp)
|
||||
{
|
||||
|
||||
P25ChannelGrantEvent event = mChannelGrantEventMap.get(apco25Channel);
|
||||
|
||||
if(event != null && isSameCall(identifierCollection, event.getIdentifierCollection()))
|
||||
@@ -189,10 +302,9 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
|
||||
|
||||
//Even though we have an event, the initial channel grant may have been rejected. Check to see if there
|
||||
//is a traffic channel allocated. If not, allocate one and update the event description.
|
||||
if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel) &&
|
||||
!(mIgnoreDataCalls && opcode == Opcode.OSP_SNDCP_DATA_CHANNEL_GRANT))
|
||||
if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel) && !(mIgnoreDataCalls && opcode.isDataChannelGrant()))
|
||||
{
|
||||
Channel trafficChannel = mAvailableTrafficChannelQueue.poll();
|
||||
Channel trafficChannel = mAvailablePhase1TrafficChannelQueue.poll();
|
||||
|
||||
if(trafficChannel != null)
|
||||
{
|
||||
@@ -211,7 +323,7 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
|
||||
return;
|
||||
}
|
||||
|
||||
if(mIgnoreDataCalls && opcode == Opcode.OSP_SNDCP_DATA_CHANNEL_GRANT)
|
||||
if(mIgnoreDataCalls && opcode.isDataChannelGrant())
|
||||
{
|
||||
P25ChannelGrantEvent channelGrantEvent = P25ChannelGrantEvent.builder(timestamp, serviceOptions)
|
||||
.channel(apco25Channel)
|
||||
@@ -239,7 +351,135 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
|
||||
//NOTE: we could also allocate a traffic channel for the uplink frequency here, in the future
|
||||
if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel))
|
||||
{
|
||||
Channel trafficChannel = mAvailableTrafficChannelQueue.poll();
|
||||
Channel trafficChannel = mAvailablePhase1TrafficChannelQueue.poll();
|
||||
|
||||
if(trafficChannel == null)
|
||||
{
|
||||
channelGrantEvent.setDetails(MAX_TRAFFIC_CHANNELS_EXCEEDED);
|
||||
channelGrantEvent.setEventDescription(channelGrantEvent.getEventDescription() + " - Ignored");
|
||||
return;
|
||||
}
|
||||
|
||||
SourceConfigTuner sourceConfig = new SourceConfigTuner();
|
||||
sourceConfig.setFrequency(apco25Channel.getDownlinkFrequency());
|
||||
trafficChannel.setSourceConfiguration(sourceConfig);
|
||||
mAllocatedTrafficChannelMap.put(apco25Channel, trafficChannel);
|
||||
broadcast(new ChannelGrantEvent(trafficChannel, Event.REQUEST_ENABLE, apco25Channel, identifierCollection));
|
||||
}
|
||||
|
||||
broadcast(channelGrantEvent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes Phase 2 channel grants to allocate traffic channels and track overall channel usage. Generates
|
||||
* decode events for each new channel that is allocated.
|
||||
*
|
||||
* @param apco25Channel for the traffic channel
|
||||
* @param serviceOptions for the traffic channel - optional can be null
|
||||
* @param identifierCollection associated with the channel grant
|
||||
* @param opcode to identify the call type for the event description
|
||||
*/
|
||||
private void processPhase2ChannelGrant(APCO25Channel apco25Channel, ServiceOptions serviceOptions,
|
||||
IdentifierCollection identifierCollection, Opcode opcode, long timestamp)
|
||||
{
|
||||
if(mPhase2ScrambleParameters != null && identifierCollection instanceof MutableIdentifierCollection)
|
||||
{
|
||||
((MutableIdentifierCollection)identifierCollection).silentUpdate(ScrambleParameterIdentifier.create(mPhase2ScrambleParameters));
|
||||
}
|
||||
|
||||
P25ChannelGrantEvent event = mChannelGrantEventMap.get(apco25Channel);
|
||||
|
||||
identifierCollection.setTimeslot(apco25Channel.getTimeslot());
|
||||
|
||||
if(event != null && isSameCall(identifierCollection, event.getIdentifierCollection()))
|
||||
{
|
||||
Identifier from = getIdentifier(identifierCollection, Role.FROM);
|
||||
|
||||
if(from != null)
|
||||
{
|
||||
Identifier currentFrom = getIdentifier(event.getIdentifierCollection(), Role.FROM);
|
||||
if(currentFrom != null && !Objects.equals(from, currentFrom))
|
||||
{
|
||||
event.end(timestamp);
|
||||
|
||||
P25ChannelGrantEvent continuationGrantEvent = P25ChannelGrantEvent.builder(timestamp, serviceOptions)
|
||||
.channel(apco25Channel)
|
||||
.eventDescription(getEventType(opcode, serviceOptions).toString() + " - Continue")
|
||||
.details("CHANNEL GRANT " + (serviceOptions != null ? serviceOptions : "UNKNOWN SERVICE OPTIONS"))
|
||||
.identifiers(identifierCollection)
|
||||
.build();
|
||||
|
||||
mChannelGrantEventMap.put(apco25Channel, continuationGrantEvent);
|
||||
broadcast(continuationGrantEvent);
|
||||
}
|
||||
}
|
||||
|
||||
//update the ending timestamp so that the duration value is correctly calculated
|
||||
event.update(timestamp);
|
||||
broadcast(event);
|
||||
|
||||
//Even though we have an event, the initial channel grant may have been rejected. Check to see if there
|
||||
//is a traffic channel allocated. If not, allocate one and update the event description.
|
||||
if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel) &&
|
||||
!(mIgnoreDataCalls && opcode.isDataChannelGrant()))
|
||||
{
|
||||
Channel trafficChannel = mAvailablePhase2TrafficChannelQueue.poll();
|
||||
|
||||
if(trafficChannel != null)
|
||||
{
|
||||
event.setEventDescription(getEventType(opcode, serviceOptions).toString());
|
||||
event.setDetails("CHANNEL GRANT " + (serviceOptions != null ? serviceOptions : "UNKNOWN SERVICE OPTIONS"));
|
||||
event.setChannelDescriptor(apco25Channel);
|
||||
broadcast(event);
|
||||
SourceConfigTuner sourceConfig = new SourceConfigTuner();
|
||||
sourceConfig.setFrequency(apco25Channel.getDownlinkFrequency());
|
||||
trafficChannel.setSourceConfiguration(sourceConfig);
|
||||
mAllocatedTrafficChannelMap.put(apco25Channel, trafficChannel);
|
||||
|
||||
//If we have valid scramble/randomizer parameters, set them in the decode config
|
||||
if(mPhase2ScrambleParameters != null)
|
||||
{
|
||||
DecodeConfigP25Phase2 decodeConfig = (DecodeConfigP25Phase2)trafficChannel.getDecodeConfiguration();
|
||||
decodeConfig.setScrambleParameters(mPhase2ScrambleParameters.copy());
|
||||
}
|
||||
|
||||
broadcast(new ChannelGrantEvent(trafficChannel, Event.REQUEST_ENABLE, apco25Channel, identifierCollection));
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(mIgnoreDataCalls && opcode.isDataChannelGrant())
|
||||
{
|
||||
P25ChannelGrantEvent channelGrantEvent = P25ChannelGrantEvent.builder(timestamp, serviceOptions)
|
||||
.channel(apco25Channel)
|
||||
.eventDescription(getEventType(opcode, serviceOptions).toString() + " - Ignored")
|
||||
.details("DATA CALL IGNORED: " + (serviceOptions != null ? serviceOptions : "UNKNOWN SERVICE OPTIONS"))
|
||||
.identifiers(identifierCollection)
|
||||
.build();
|
||||
|
||||
mChannelGrantEventMap.put(apco25Channel, channelGrantEvent);
|
||||
|
||||
broadcast(channelGrantEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
P25ChannelGrantEvent channelGrantEvent = P25ChannelGrantEvent.builder(timestamp, serviceOptions)
|
||||
.channel(apco25Channel)
|
||||
.eventDescription(getEventType(opcode, serviceOptions).toString())
|
||||
.details("CHANNEL GRANT " + (serviceOptions != null ? serviceOptions : "UNKNOWN SERVICE OPTIONS"))
|
||||
.identifiers(identifierCollection)
|
||||
.build();
|
||||
|
||||
mChannelGrantEventMap.put(apco25Channel, channelGrantEvent);
|
||||
|
||||
//Allocate a traffic channel for the downlink frequency if one isn't already allocated
|
||||
//NOTE: we could also allocate a traffic channel for the uplink frequency here, in the future
|
||||
if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel))
|
||||
{
|
||||
Channel trafficChannel = mAvailablePhase2TrafficChannelQueue.poll();
|
||||
|
||||
if(trafficChannel == null)
|
||||
{
|
||||
@@ -382,14 +622,10 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
for(Channel trafficChannel : mAvailableTrafficChannelQueue)
|
||||
for(Channel trafficChannel : mAvailablePhase1TrafficChannelQueue)
|
||||
{
|
||||
broadcast(new ChannelEvent(trafficChannel, Event.REQUEST_DISABLE));
|
||||
}
|
||||
|
||||
mAvailableTrafficChannelQueue.clear();
|
||||
|
||||
// mTrafficChannelsInUse.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -433,6 +669,66 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the decoded message stream and captures P25 Phase II randomizer (scramble) parameters from the TSBK
|
||||
* network status broadcast message so that we can pre-load any Phase2 channels with the correct descrambler
|
||||
* sequence.
|
||||
*
|
||||
* @return listener to process the message stream.
|
||||
*/
|
||||
@Override
|
||||
public Listener<IMessage> getMessageListener()
|
||||
{
|
||||
if(mMessageListener == null)
|
||||
{
|
||||
mMessageListener = new Listener<IMessage>()
|
||||
{
|
||||
@Override
|
||||
public void receive(IMessage message)
|
||||
{
|
||||
if(mPhase2ScrambleParameters == null && message.isValid())
|
||||
{
|
||||
if(message instanceof NetworkStatusBroadcast)
|
||||
{
|
||||
mPhase2ScrambleParameters = ((NetworkStatusBroadcast)message).getScrambleParameters();
|
||||
}
|
||||
else if(message instanceof AMBTCNetworkStatusBroadcast)
|
||||
{
|
||||
mPhase2ScrambleParameters = ((AMBTCNetworkStatusBroadcast)message).getScrambleParameters();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return mMessageListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a phase 2 channel to a phase 1 channel
|
||||
* @param channel to convert
|
||||
* @return channel converted to phase 1 or the original channel if no conversion is necessary
|
||||
*/
|
||||
private static APCO25Channel convertPhase2ToPhase1(APCO25Channel channel)
|
||||
{
|
||||
P25Channel toConvert = channel.getValue();
|
||||
|
||||
if(toConvert instanceof P25P2ExplicitChannel)
|
||||
{
|
||||
P25P2ExplicitChannel phase2 = (P25P2ExplicitChannel)toConvert;
|
||||
return APCO25ExplicitChannel.create(phase2.getDownlinkBandIdentifier(),
|
||||
phase2.getDownlinkChannelNumber(), phase2.getUplinkBandIdentifier(),
|
||||
phase2.getUplinkChannelNumber());
|
||||
}
|
||||
else if(toConvert instanceof P25P2Channel)
|
||||
{
|
||||
P25P2Channel phase2 = (P25P2Channel)toConvert;
|
||||
return APCO25Channel.create(phase2.getDownlinkBandIdentifier(), phase2.getDownlinkChannelNumber());
|
||||
}
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors channel teardown events to detect when traffic channel processing has ended. Reclaims the
|
||||
* channel instance for reuse by future traffic channel grants.
|
||||
@@ -444,70 +740,94 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
|
||||
{
|
||||
Channel channel = channelEvent.getChannel();
|
||||
|
||||
if(channel.isTrafficChannel() && mManagedTrafficChannels.contains(channel))
|
||||
if(channel.isTrafficChannel())
|
||||
{
|
||||
switch(channelEvent.getEvent())
|
||||
boolean isPhase1 = channel.getDecodeConfiguration().getDecoderType() == DecoderType.P25_PHASE1;
|
||||
|
||||
if((isPhase1 && mManagedPhase1TrafficChannels.contains(channel)) ||
|
||||
(!isPhase1 && mManagedPhase2TrafficChannels.contains(channel)))
|
||||
{
|
||||
case NOTIFICATION_PROCESSING_STOP:
|
||||
APCO25Channel toRemove = null;
|
||||
switch(channelEvent.getEvent())
|
||||
{
|
||||
case NOTIFICATION_PROCESSING_STOP:
|
||||
APCO25Channel toRemove = null;
|
||||
|
||||
for(Map.Entry<APCO25Channel,Channel> entry: mAllocatedTrafficChannelMap.entrySet())
|
||||
{
|
||||
if(entry.getValue() == channel)
|
||||
for(Map.Entry<APCO25Channel,Channel> entry: mAllocatedTrafficChannelMap.entrySet())
|
||||
{
|
||||
toRemove = entry.getKey();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(toRemove != null)
|
||||
{
|
||||
mAllocatedTrafficChannelMap.remove(toRemove);
|
||||
mAvailableTrafficChannelQueue.add(channel);
|
||||
P25ChannelGrantEvent event = mChannelGrantEventMap.remove(toRemove);
|
||||
|
||||
if(event != null)
|
||||
{
|
||||
event.end(System.currentTimeMillis());
|
||||
broadcast(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NOTIFICATION_PROCESSING_START_REJECTED:
|
||||
APCO25Channel rejected = null;
|
||||
|
||||
for(Map.Entry<APCO25Channel,Channel> entry: mAllocatedTrafficChannelMap.entrySet())
|
||||
{
|
||||
if(entry.getValue() == channel)
|
||||
{
|
||||
rejected = entry.getKey();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(rejected != null)
|
||||
{
|
||||
mAllocatedTrafficChannelMap.remove(rejected);
|
||||
mAvailableTrafficChannelQueue.add(channel);
|
||||
P25ChannelGrantEvent event = mChannelGrantEventMap.get(rejected);
|
||||
|
||||
if(event != null)
|
||||
{
|
||||
event.setEventDescription(event.getEventDescription() + " - Rejected");
|
||||
|
||||
if(channelEvent.getDescription() != null)
|
||||
if(entry.getValue() == channel)
|
||||
{
|
||||
event.setDetails(channelEvent.getDescription() + " - " + event.getDetails());
|
||||
toRemove = entry.getKey();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(toRemove != null)
|
||||
{
|
||||
mAllocatedTrafficChannelMap.remove(toRemove);
|
||||
|
||||
if(isPhase1)
|
||||
{
|
||||
mAvailablePhase1TrafficChannelQueue.add(channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
event.setDetails(CHANNEL_START_REJECTED + " - " + event.getDetails());
|
||||
mAvailablePhase2TrafficChannelQueue.add(channel);
|
||||
}
|
||||
|
||||
broadcast(event);
|
||||
P25ChannelGrantEvent event = mChannelGrantEventMap.remove(toRemove);
|
||||
|
||||
if(event != null)
|
||||
{
|
||||
event.end(System.currentTimeMillis());
|
||||
broadcast(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case NOTIFICATION_PROCESSING_START_REJECTED:
|
||||
APCO25Channel rejected = null;
|
||||
|
||||
for(Map.Entry<APCO25Channel,Channel> entry: mAllocatedTrafficChannelMap.entrySet())
|
||||
{
|
||||
if(entry.getValue() == channel)
|
||||
{
|
||||
rejected = entry.getKey();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(rejected != null)
|
||||
{
|
||||
mAllocatedTrafficChannelMap.remove(rejected);
|
||||
|
||||
if(isPhase1)
|
||||
{
|
||||
mAvailablePhase1TrafficChannelQueue.add(channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
mAvailablePhase2TrafficChannelQueue.add(channel);
|
||||
}
|
||||
|
||||
P25ChannelGrantEvent event = mChannelGrantEventMap.get(rejected);
|
||||
|
||||
if(event != null)
|
||||
{
|
||||
event.setEventDescription(event.getEventDescription() + " - Rejected");
|
||||
|
||||
if(channelEvent.getDescription() != null)
|
||||
{
|
||||
event.setDetails(channelEvent.getDescription() + " - " + event.getDetails());
|
||||
}
|
||||
else
|
||||
{
|
||||
event.setDetails(CHANNEL_START_REJECTED + " - " + event.getDetails());
|
||||
}
|
||||
|
||||
broadcast(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,366 +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.audio;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import io.github.dsheirer.audio.AbstractAudioModule;
|
||||
import io.github.dsheirer.audio.AudioFormats;
|
||||
import io.github.dsheirer.audio.squelch.SquelchState;
|
||||
import io.github.dsheirer.dsp.gain.NonClippingGain;
|
||||
import io.github.dsheirer.eventbus.MyEventBus;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.message.IMessageListener;
|
||||
import io.github.dsheirer.module.decode.p25.message.hdu.HDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.ldu.LDU1Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.ldu.LDU2Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.ldu.LDUMessage;
|
||||
import io.github.dsheirer.preference.PreferenceType;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacketQueue;
|
||||
import jmbe.iface.AudioConversionLibrary;
|
||||
import jmbe.iface.AudioConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class P25AudioModule extends AbstractAudioModule implements Listener<IMessage>, IMessageListener
|
||||
{
|
||||
private static final Logger mLog = LoggerFactory.getLogger(P25AudioModule.class);
|
||||
private static final String IMBE_CODEC = "IMBE";
|
||||
private static boolean mLibraryLoadStatusLogged = false;
|
||||
|
||||
private boolean mCanConvertAudio = false;
|
||||
private boolean mEncryptedCall = false;
|
||||
private boolean mEncryptedCallStateEstablished = false;
|
||||
|
||||
private AudioConverter mAudioConverter;
|
||||
private SquelchStateListener mSquelchStateListener = new SquelchStateListener();
|
||||
private NonClippingGain mGain = new NonClippingGain(5.0f, 0.95f);
|
||||
private LDU1Message mCachedLDU1Message = null;
|
||||
private ReusableAudioPacketQueue mAudioPacketQueue = new ReusableAudioPacketQueue("P25AudioModule");
|
||||
private UserPreferences mUserPreferences;
|
||||
|
||||
public P25AudioModule(UserPreferences userPreferences)
|
||||
{
|
||||
mUserPreferences = userPreferences;
|
||||
MyEventBus.getEventBus().register(this);
|
||||
loadConverter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<IMessage> getMessageListener()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<SquelchState> getSquelchStateListener()
|
||||
{
|
||||
return mSquelchStateListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
mAudioConverter = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
getIdentifierCollection().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
if(hasAudioPacketListener())
|
||||
{
|
||||
ReusableAudioPacket endAudioPacket = mAudioPacketQueue.getEndAudioBuffer();
|
||||
endAudioPacket.resetAttributes();
|
||||
endAudioPacket.setAudioChannelId(getAudioChannelId());
|
||||
endAudioPacket.setIdentifierCollection(getIdentifierCollection().copyOf());
|
||||
endAudioPacket.incrementUserCount();
|
||||
getAudioPacketListener().receive(endAudioPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes call header (HDU) and voice frame (LDU1/LDU2) messages to decode audio and to determine the
|
||||
* encrypted audio status of a call event. Only the HDU and LDU2 messages convey encrypted call status. If an
|
||||
* LDU1 message is received without a preceding HDU message, then the LDU1 message is cached until the first
|
||||
* LDU2 message is received and the encryption state can be determined. Both the LDU1 and the LDU2 message are
|
||||
* then processed for audio if the call is unencrypted.
|
||||
*/
|
||||
public void receive(IMessage message)
|
||||
{
|
||||
if(mCanConvertAudio && hasAudioPacketListener())
|
||||
{
|
||||
if(mEncryptedCallStateEstablished)
|
||||
{
|
||||
if(message instanceof LDUMessage)
|
||||
{
|
||||
processAudio((LDUMessage)message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(message instanceof HDUMessage)
|
||||
{
|
||||
mEncryptedCallStateEstablished = true;
|
||||
mEncryptedCall = ((HDUMessage)message).getHeaderData().isEncryptedAudio();
|
||||
}
|
||||
else if(message instanceof LDU1Message)
|
||||
{
|
||||
//When we receive an LDU1 message without first receiving the HDU message, cache the LDU1 Message
|
||||
//until we can determine the encrypted call state from the next LDU2 message
|
||||
mCachedLDU1Message = (LDU1Message)message;
|
||||
}
|
||||
else if(message instanceof LDU2Message)
|
||||
{
|
||||
mEncryptedCallStateEstablished = true;
|
||||
LDU2Message ldu2 = (LDU2Message)message;
|
||||
mEncryptedCall = ldu2.getEncryptionSyncParameters().isEncryptedAudio();
|
||||
|
||||
if(mCachedLDU1Message != null)
|
||||
{
|
||||
processAudio(mCachedLDU1Message);
|
||||
mCachedLDU1Message = null;
|
||||
}
|
||||
|
||||
processAudio(ldu2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an audio packet by decoding the IMBE audio frames and rebroadcasting them as PCM audio packets.
|
||||
*/
|
||||
private void processAudio(LDUMessage ldu)
|
||||
{
|
||||
if(!mEncryptedCall)
|
||||
{
|
||||
for(byte[] frame : ldu.getIMBEFrames())
|
||||
{
|
||||
float[] audio = mAudioConverter.decode(frame);
|
||||
|
||||
audio = mGain.apply(audio);
|
||||
|
||||
ReusableAudioPacket audioPacket = mAudioPacketQueue.getBuffer(audio.length);
|
||||
audioPacket.resetAttributes();
|
||||
audioPacket.setAudioChannelId(getAudioChannelId());
|
||||
audioPacket.setIdentifierCollection(getIdentifierCollection().copyOf());
|
||||
audioPacket.loadAudioFrom(audio);
|
||||
|
||||
getAudioPacketListener().receive(audioPacket);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Encrypted audio processing not implemented
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives notifications that the JMBE library preference has been updated via the Guava event bus
|
||||
*
|
||||
* @param preferenceType that was updated
|
||||
*/
|
||||
@Subscribe
|
||||
public void preferenceUpdated(PreferenceType preferenceType)
|
||||
{
|
||||
if(preferenceType == PreferenceType.JMBE_LIBRARY)
|
||||
{
|
||||
mLibraryLoadStatusLogged = false;
|
||||
loadConverter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads audio frame processing chain. Constructs an imbe targetdataline
|
||||
* to receive the raw imbe frames. Adds an IMBE to 8k PCM format conversion
|
||||
* stream wrapper. Finally, adds an upsampling (8k to 48k) stream wrapper.
|
||||
*/
|
||||
private void loadConverter()
|
||||
{
|
||||
AudioConverter audioConverter = null;
|
||||
|
||||
Path path = mUserPreferences.getJmbeLibraryPreference().getPathJmbeLibrary();
|
||||
|
||||
if(path != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.info("Loading JMBE library from [" + path.toString() + "]");
|
||||
}
|
||||
|
||||
URLClassLoader childClassLoader = new URLClassLoader(new URL[]{path.toUri().toURL()},
|
||||
this.getClass().getClassLoader());
|
||||
|
||||
Class classToLoad = Class.forName("jmbe.JMBEAudioLibrary", true, childClassLoader);
|
||||
|
||||
Object instance = classToLoad.getDeclaredConstructor().newInstance();
|
||||
|
||||
if(instance instanceof AudioConversionLibrary)
|
||||
{
|
||||
AudioConversionLibrary library = (AudioConversionLibrary)instance;
|
||||
|
||||
if((library.getMajorVersion() == 0 && library.getMinorVersion() >= 3 &&
|
||||
library.getBuildVersion() >= 3) || library.getMajorVersion() >= 1)
|
||||
{
|
||||
audioConverter = library.getAudioConverter(IMBE_CODEC, AudioFormats.PCM_SIGNED_8KHZ_16BITS_MONO);
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("JMBE library version 0.3.3 or higher is required - found: " + library.getVersion());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.info("JMBE audio conversion library NOT FOUND");
|
||||
mLibraryLoadStatusLogged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(NoSuchMethodException nsme)
|
||||
{
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.error("Couldn't load JMBE audio conversion library - no such method exception");
|
||||
mLibraryLoadStatusLogged = true;
|
||||
}
|
||||
}
|
||||
catch(MalformedURLException mue)
|
||||
{
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.error("Couldn't load JMBE audio conversion library from path [" + path + "]");
|
||||
mLibraryLoadStatusLogged = true;
|
||||
}
|
||||
}
|
||||
catch(ClassNotFoundException e1)
|
||||
{
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.error("Couldn't load JMBE audio conversion library - class not found");
|
||||
mLibraryLoadStatusLogged = true;
|
||||
}
|
||||
}
|
||||
catch(InvocationTargetException ite)
|
||||
{
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.error("Couldn't load JMBE audio conversion library - invocation target exception", ite);
|
||||
mLibraryLoadStatusLogged = true;
|
||||
}
|
||||
}
|
||||
catch(InstantiationException e1)
|
||||
{
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.error("Couldn't load JMBE audio conversion library - instantiation exception", e1);
|
||||
mLibraryLoadStatusLogged = true;
|
||||
}
|
||||
}
|
||||
catch(IllegalAccessException e1)
|
||||
{
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.error("Couldn't load JMBE audio conversion library - security restrictions");
|
||||
mLibraryLoadStatusLogged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.info("JMBE audio library path is NOT SET in your User Preferences.");
|
||||
}
|
||||
|
||||
if(audioConverter != null)
|
||||
{
|
||||
mAudioConverter = audioConverter;
|
||||
mCanConvertAudio = true;
|
||||
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.info("JMBE audio conversion library successfully loaded - P25 audio will be available");
|
||||
mLibraryLoadStatusLogged = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mCanConvertAudio = false;
|
||||
mAudioConverter = null;
|
||||
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.info("JMBE audio conversion library NOT FOUND");
|
||||
mLibraryLoadStatusLogged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for squelch state to process end of call actions. At call end the encrypted call state established
|
||||
* flag is reset so that the encrypted audio state for the next call can be properly detected and we send an
|
||||
* END audio packet so that downstream processors like the audio recorder can properly close out a call sequence.
|
||||
*/
|
||||
public class SquelchStateListener implements Listener<SquelchState>
|
||||
{
|
||||
@Override
|
||||
public void receive(SquelchState state)
|
||||
{
|
||||
if(state == SquelchState.SQUELCH)
|
||||
{
|
||||
if(hasAudioPacketListener())
|
||||
{
|
||||
ReusableAudioPacket endAudioPacket = mAudioPacketQueue.getEndAudioBuffer();
|
||||
endAudioPacket.resetAttributes();
|
||||
endAudioPacket.setAudioChannelId(getAudioChannelId());
|
||||
endAudioPacket.setIdentifierCollection(getIdentifierCollection().copyOf());
|
||||
endAudioPacket.incrementUserCount();
|
||||
getAudioPacketListener().receive(endAudioPacket);
|
||||
}
|
||||
|
||||
mEncryptedCallStateEstablished = false;
|
||||
mEncryptedCall = false;
|
||||
mCachedLDU1Message = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * 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.audio;
|
||||
|
||||
import io.github.dsheirer.audio.codec.mbe.ImbeAudioModule;
|
||||
import io.github.dsheirer.audio.squelch.SquelchState;
|
||||
import io.github.dsheirer.audio.squelch.SquelchStateEvent;
|
||||
import io.github.dsheirer.dsp.gain.NonClippingGain;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.hdu.HDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU1Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU2Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDUMessage;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
|
||||
public class P25P1AudioModule extends ImbeAudioModule
|
||||
{
|
||||
private boolean mEncryptedCall = false;
|
||||
private boolean mEncryptedCallStateEstablished = false;
|
||||
|
||||
private SquelchStateListener mSquelchStateListener = new SquelchStateListener();
|
||||
private NonClippingGain mGain = new NonClippingGain(5.0f, 0.95f);
|
||||
private LDU1Message mCachedLDU1Message = null;
|
||||
|
||||
public P25P1AudioModule(UserPreferences userPreferences)
|
||||
{
|
||||
super(userPreferences);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<SquelchStateEvent> getSquelchStateListener()
|
||||
{
|
||||
return mSquelchStateListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
getIdentifierCollection().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
if(hasAudioPacketListener())
|
||||
{
|
||||
ReusableAudioPacket endAudioPacket = getAudioPacketQueue().getEndAudioBuffer();
|
||||
endAudioPacket.resetAttributes();
|
||||
endAudioPacket.setAudioChannelId(getAudioChannelId());
|
||||
endAudioPacket.setIdentifierCollection(getIdentifierCollection().copyOf());
|
||||
endAudioPacket.incrementUserCount();
|
||||
getAudioPacketListener().receive(endAudioPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes call header (HDU) and voice frame (LDU1/LDU2) messages to decode audio and to determine the
|
||||
* encrypted audio status of a call event. Only the HDU and LDU2 messages convey encrypted call status. If an
|
||||
* LDU1 message is received without a preceding HDU message, then the LDU1 message is cached until the first
|
||||
* LDU2 message is received and the encryption state can be determined. Both the LDU1 and the LDU2 message are
|
||||
* then processed for audio if the call is unencrypted.
|
||||
*/
|
||||
public void receive(IMessage message)
|
||||
{
|
||||
if(hasAudioCodec() && hasAudioPacketListener())
|
||||
{
|
||||
if(mEncryptedCallStateEstablished)
|
||||
{
|
||||
if(message instanceof LDUMessage)
|
||||
{
|
||||
processAudio((LDUMessage)message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(message instanceof HDUMessage)
|
||||
{
|
||||
mEncryptedCallStateEstablished = true;
|
||||
mEncryptedCall = ((HDUMessage)message).getHeaderData().isEncryptedAudio();
|
||||
}
|
||||
else if(message instanceof LDU1Message)
|
||||
{
|
||||
//When we receive an LDU1 message without first receiving the HDU message, cache the LDU1 Message
|
||||
//until we can determine the encrypted call state from the next LDU2 message
|
||||
mCachedLDU1Message = (LDU1Message)message;
|
||||
}
|
||||
else if(message instanceof LDU2Message)
|
||||
{
|
||||
mEncryptedCallStateEstablished = true;
|
||||
LDU2Message ldu2 = (LDU2Message)message;
|
||||
mEncryptedCall = ldu2.getEncryptionSyncParameters().isEncryptedAudio();
|
||||
|
||||
if(mCachedLDU1Message != null)
|
||||
{
|
||||
processAudio(mCachedLDU1Message);
|
||||
mCachedLDU1Message = null;
|
||||
}
|
||||
|
||||
processAudio(ldu2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an audio packet by decoding the IMBE audio frames and rebroadcasting them as PCM audio packets.
|
||||
*/
|
||||
private void processAudio(LDUMessage ldu)
|
||||
{
|
||||
if(!mEncryptedCall)
|
||||
{
|
||||
for(byte[] frame : ldu.getIMBEFrames())
|
||||
{
|
||||
float[] audio = getAudioCodec().getAudio(frame);
|
||||
|
||||
audio = mGain.apply(audio);
|
||||
|
||||
ReusableAudioPacket audioPacket = getAudioPacketQueue().getBuffer(audio.length);
|
||||
audioPacket.resetAttributes();
|
||||
audioPacket.setAudioChannelId(getAudioChannelId());
|
||||
audioPacket.setIdentifierCollection(getIdentifierCollection().copyOf());
|
||||
audioPacket.loadAudioFrom(audio);
|
||||
|
||||
getAudioPacketListener().receive(audioPacket);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Encrypted audio processing not implemented
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for squelch state to process end of call actions. At call end the encrypted call state established
|
||||
* flag is reset so that the encrypted audio state for the next call can be properly detected and we send an
|
||||
* END audio packet so that downstream processors like the audio recorder can properly close out a call sequence.
|
||||
*/
|
||||
public class SquelchStateListener implements Listener<SquelchStateEvent>
|
||||
{
|
||||
@Override
|
||||
public void receive(SquelchStateEvent event)
|
||||
{
|
||||
if(event.getSquelchState() == SquelchState.SQUELCH)
|
||||
{
|
||||
if(hasAudioPacketListener())
|
||||
{
|
||||
ReusableAudioPacket endAudioPacket = getAudioPacketQueue().getEndAudioBuffer();
|
||||
endAudioPacket.resetAttributes();
|
||||
endAudioPacket.setAudioChannelId(getAudioChannelId());
|
||||
endAudioPacket.setIdentifierCollection(getIdentifierCollection().copyOf());
|
||||
endAudioPacket.incrementUserCount();
|
||||
getAudioPacketListener().receive(endAudioPacket);
|
||||
}
|
||||
|
||||
mEncryptedCallStateEstablished = false;
|
||||
mEncryptedCall = false;
|
||||
mCachedLDU1Message = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * 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.audio;
|
||||
|
||||
|
||||
import io.github.dsheirer.audio.codec.mbe.MBECallSequence;
|
||||
import io.github.dsheirer.audio.codec.mbe.MBECallSequenceRecorder;
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.P25Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaPatchGroupVoiceChannelUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaPatchGroupVoiceChannelUser;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupVoiceChannelUpdateExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupVoiceChannelUser;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCTelephoneInterconnectVoiceChannelUser;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCUnitToUnitVoiceChannelUser;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.EncryptionSyncParameters;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU1Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU2Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDULinkControlMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDUMessage;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* P25 Phase 1 IMBE Frame recorder generates P25 call sequence recordings containing JSON representations of audio
|
||||
* frames, optional encryption and call identifiers.
|
||||
*/
|
||||
public class P25P1CallSequenceRecorder extends MBECallSequenceRecorder
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P1CallSequenceRecorder.class);
|
||||
|
||||
private static final String PROTOCOL = "APCO25-PHASE1";
|
||||
|
||||
private MBECallSequence mCallSequence;
|
||||
|
||||
/**
|
||||
* Constructs a P25-Phase2 MBE call sequence recorder.
|
||||
*
|
||||
* @param userPreferences to obtain the recording directory
|
||||
* @param channelFrequency for the channel to record
|
||||
* @param system defined by the user
|
||||
* @param site defined by the user
|
||||
*/
|
||||
public P25P1CallSequenceRecorder(UserPreferences userPreferences, long channelFrequency, String system, String site)
|
||||
{
|
||||
super(userPreferences, channelFrequency, system, site);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops and flushes any partial frame sequence from the processors
|
||||
*/
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary message interface for receiving frames and metadata messages to record
|
||||
*/
|
||||
@Override
|
||||
public void receive(IMessage message)
|
||||
{
|
||||
if(message instanceof P25Message)
|
||||
{
|
||||
P25Message p25 = (P25Message)message;
|
||||
|
||||
if(p25.isValid())
|
||||
{
|
||||
process(p25);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Flushes any partial call sequence
|
||||
*/
|
||||
public void flush()
|
||||
{
|
||||
if(mCallSequence != null)
|
||||
{
|
||||
writeCallSequence(mCallSequence);
|
||||
mCallSequence = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes any P25 Phase 1 message
|
||||
*/
|
||||
public void process(P25Message message)
|
||||
{
|
||||
if(message instanceof LDUMessage)
|
||||
{
|
||||
process((LDUMessage)message);
|
||||
}
|
||||
else if(message instanceof TDULinkControlMessage)
|
||||
{
|
||||
process((TDULinkControlMessage)message);
|
||||
}
|
||||
else if(message instanceof TDUMessage)
|
||||
{
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
private void process(TDULinkControlMessage tdulc)
|
||||
{
|
||||
process(tdulc.getLinkControlWord());
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes Voice LDU messages
|
||||
*/
|
||||
private void process(LDUMessage lduMessage)
|
||||
{
|
||||
if(mCallSequence == null)
|
||||
{
|
||||
mCallSequence = new MBECallSequence(PROTOCOL);
|
||||
}
|
||||
|
||||
if(lduMessage instanceof LDU1Message)
|
||||
{
|
||||
process((LDU1Message)lduMessage);
|
||||
}
|
||||
else if(lduMessage instanceof LDU2Message)
|
||||
{
|
||||
process((LDU2Message)lduMessage);
|
||||
}
|
||||
|
||||
List<byte[]> voiceFrames = lduMessage.getIMBEFrames();
|
||||
|
||||
long baseTimestamp = lduMessage.getTimestamp();
|
||||
|
||||
for(byte[] frame : voiceFrames)
|
||||
{
|
||||
BinaryMessage frameBits = BinaryMessage.from(frame);
|
||||
mCallSequence.addVoiceFrame(baseTimestamp, frameBits.toHexString());
|
||||
|
||||
//Voice frames are 20 milliseconds each, so we increment the timestamp by 20 for each one
|
||||
baseTimestamp += 20;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void process(LinkControlWord lcw)
|
||||
{
|
||||
if(lcw.isValid() && mCallSequence != null)
|
||||
{
|
||||
switch(lcw.getOpcode())
|
||||
{
|
||||
case GROUP_VOICE_CHANNEL_USER:
|
||||
LCGroupVoiceChannelUser gvcu = (LCGroupVoiceChannelUser)lcw;
|
||||
mCallSequence.setFromIdentifier(gvcu.getSourceAddress().toString());
|
||||
mCallSequence.setToIdentifier(gvcu.getGroupAddress().toString());
|
||||
mCallSequence.setCallType(CALL_TYPE_GROUP);
|
||||
break;
|
||||
case UNIT_TO_UNIT_VOICE_CHANNEL_USER:
|
||||
LCUnitToUnitVoiceChannelUser uuvcu = (LCUnitToUnitVoiceChannelUser)lcw;
|
||||
mCallSequence.setFromIdentifier(uuvcu.getSourceAddress().toString());
|
||||
mCallSequence.setToIdentifier(uuvcu.getTargetAddress().toString());
|
||||
mCallSequence.setCallType(CALL_TYPE_INDIVIDUAL);
|
||||
break;
|
||||
case GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT:
|
||||
LCGroupVoiceChannelUpdateExplicit gvcue = (LCGroupVoiceChannelUpdateExplicit)lcw;
|
||||
mCallSequence.setToIdentifier(gvcue.getGroupAddress().toString());
|
||||
mCallSequence.setCallType(CALL_TYPE_GROUP);
|
||||
break;
|
||||
case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER:
|
||||
LCTelephoneInterconnectVoiceChannelUser tivcu = (LCTelephoneInterconnectVoiceChannelUser)lcw;
|
||||
mCallSequence.setToIdentifier(tivcu.getAddress().toString());
|
||||
mCallSequence.setCallType(CALL_TYPE_TELEPHONE_INTERCONNECT);
|
||||
break;
|
||||
case MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_USER:
|
||||
LCMotorolaPatchGroupVoiceChannelUser mpgvcu = (LCMotorolaPatchGroupVoiceChannelUser)lcw;
|
||||
mCallSequence.setFromIdentifier(mpgvcu.getSourceAddress().toString());
|
||||
mCallSequence.setToIdentifier(mpgvcu.getGroupAddress().toString());
|
||||
mCallSequence.setCallType(CALL_TYPE_GROUP);
|
||||
break;
|
||||
case MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_UPDATE:
|
||||
LCMotorolaPatchGroupVoiceChannelUpdate mpgvcup = (LCMotorolaPatchGroupVoiceChannelUpdate)lcw;
|
||||
mCallSequence.setToIdentifier(mpgvcup.getPatchGroup().toString());
|
||||
mCallSequence.setCallType(CALL_TYPE_GROUP);
|
||||
break;
|
||||
case CALL_TERMINATION_OR_CANCELLATION:
|
||||
case MOTOROLA_TALK_COMPLETE:
|
||||
writeCallSequence(mCallSequence);
|
||||
mCallSequence = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void process(LDU1Message ldu1Message)
|
||||
{
|
||||
process(ldu1Message.getLinkControlWord());
|
||||
}
|
||||
|
||||
private void process(LDU2Message ldu2Message)
|
||||
{
|
||||
EncryptionSyncParameters parameters = ldu2Message.getEncryptionSyncParameters();
|
||||
|
||||
if(parameters.isValid() && parameters.isEncryptedAudio())
|
||||
{
|
||||
mCallSequence.setEncrypted(true);
|
||||
mCallSequence.setEncryptionSyncParameters(parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * 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.audio;
|
||||
|
||||
import io.github.dsheirer.audio.codec.mbe.AmbeAudioModule;
|
||||
import io.github.dsheirer.audio.squelch.SquelchState;
|
||||
import io.github.dsheirer.audio.squelch.SquelchStateEvent;
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.IdentifierUpdateNotification;
|
||||
import io.github.dsheirer.identifier.IdentifierUpdateProvider;
|
||||
import io.github.dsheirer.identifier.tone.P25CallProgressIdentifier;
|
||||
import io.github.dsheirer.identifier.tone.P25DtmfIdentifier;
|
||||
import io.github.dsheirer.identifier.tone.P25KnoxIdentifier;
|
||||
import io.github.dsheirer.identifier.tone.P25ToneIdentifier;
|
||||
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;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.timeslot.AbstractVoiceTimeslot;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import jmbe.iface.IAudioWithMetadata;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
|
||||
public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdateProvider
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P2AudioModule.class);
|
||||
|
||||
private static final String METADATA_TYPE_DTMF = "DTMF";
|
||||
private static final String METADATA_TYPE_KNOX = "KNOX";
|
||||
private static final String METADATA_TYPE_TONE = "TONE";
|
||||
private static final String METADATA_TYPE_CALL_PROGRESS = "CALL PROGRESS";
|
||||
|
||||
private Listener<IdentifierUpdateNotification> mIdentifierUpdateNotificationListener;
|
||||
private MetadataProcessor mDtmfMetadataProcessor;
|
||||
private MetadataProcessor mKnoxMetadataProcessor;
|
||||
private MetadataProcessor mToneMetadataProcessor;
|
||||
private MetadataProcessor mCallProcessMetadataProcessor;
|
||||
private int mTimeslot;
|
||||
private Queue<AbstractVoiceTimeslot> mQueuedAudioTimeslots = new ArrayDeque<>();
|
||||
private boolean mEncryptedCallStateEstablished = false;
|
||||
private boolean mEncryptedCall = false;
|
||||
|
||||
public P25P2AudioModule(UserPreferences userPreferences, int timeslot)
|
||||
{
|
||||
super(userPreferences);
|
||||
mTimeslot = timeslot;
|
||||
getIdentifierCollection().setTimeslot(timeslot);
|
||||
}
|
||||
|
||||
private int getTimeslot()
|
||||
{
|
||||
return mTimeslot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<SquelchStateEvent> getSquelchStateListener()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
mCallProcessMetadataProcessor = null;
|
||||
mDtmfMetadataProcessor = null;
|
||||
mKnoxMetadataProcessor = null;
|
||||
mToneMetadataProcessor = null;
|
||||
mQueuedAudioTimeslots.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary message processing method for processing voice timeslots and Push-To-Talk MAC messages
|
||||
*
|
||||
* Audio timeslots are temporarily queued until a determination of the encrypted state of the call is determined
|
||||
* and then all queued audio is processed through to the end of the call. Encryption state is determined either
|
||||
* by the PTT MAC message or by processing the ESS fragments from the Voice2 and Voice4 timeslots.
|
||||
*
|
||||
* @param message to process
|
||||
*/
|
||||
@Override
|
||||
public void receive(IMessage message)
|
||||
{
|
||||
if(message.getTimeslot() == getTimeslot())
|
||||
{
|
||||
if(message instanceof AbstractVoiceTimeslot)
|
||||
{
|
||||
AbstractVoiceTimeslot abstractVoiceTimeslot = (AbstractVoiceTimeslot)message;
|
||||
|
||||
if(mEncryptedCallStateEstablished)
|
||||
{
|
||||
if(!mEncryptedCall)
|
||||
{
|
||||
processAudio(abstractVoiceTimeslot.getVoiceFrames());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Queue audio timeslots until we can determine if the audio is encrypted or not
|
||||
mQueuedAudioTimeslots.offer(abstractVoiceTimeslot);
|
||||
}
|
||||
}
|
||||
else if(message instanceof PushToTalk && message.isValid())
|
||||
{
|
||||
mEncryptedCallStateEstablished = true;
|
||||
mEncryptedCall = ((PushToTalk)message).isEncrypted();
|
||||
|
||||
//There should not be any pending voice timeslots to process since the PTT message is the first in
|
||||
//the audio call sequence
|
||||
}
|
||||
else if(message instanceof EncryptionSynchronizationSequence)
|
||||
{
|
||||
mEncryptedCallStateEstablished = true;
|
||||
mEncryptedCall = ((EncryptionSynchronizationSequence)message).isEncrypted();
|
||||
processPendingVoiceTimeslots();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drains and processes any audio timeslots that have been queued pending determination of encrypted call status
|
||||
*/
|
||||
private void processPendingVoiceTimeslots()
|
||||
{
|
||||
AbstractVoiceTimeslot timeslot = mQueuedAudioTimeslots.poll();
|
||||
|
||||
while(timeslot != null)
|
||||
{
|
||||
receive(timeslot);
|
||||
timeslot = mQueuedAudioTimeslots.poll();
|
||||
}
|
||||
}
|
||||
|
||||
private void processAudio(List<BinaryMessage> voiceFrames)
|
||||
{
|
||||
if(hasAudioCodec() && hasAudioPacketListener())
|
||||
{
|
||||
for(BinaryMessage voiceFrame: voiceFrames)
|
||||
{
|
||||
byte[] voiceFrameBytes = voiceFrame.getBytes();
|
||||
|
||||
IAudioWithMetadata audioWithMetadata = getAudioCodec().getAudioWithMetadata(voiceFrameBytes);
|
||||
processMetadata(audioWithMetadata);
|
||||
|
||||
ReusableAudioPacket audioPacket = getAudioPacketQueue().getBuffer(audioWithMetadata.getAudio().length);
|
||||
audioPacket.resetAttributes();
|
||||
audioPacket.setAudioChannelId(getAudioChannelId());
|
||||
audioPacket.setIdentifierCollection(getIdentifierCollection().copyOf());
|
||||
audioPacket.loadAudioFrom(audioWithMetadata.getAudio());
|
||||
getAudioPacketListener().receive(audioPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes optional metadata that can be included with decoded audio (ie dtmf, tones, knox, etc.)
|
||||
*/
|
||||
private void processMetadata(IAudioWithMetadata audioWithMetadata)
|
||||
{
|
||||
if(mIdentifierUpdateNotificationListener != null)
|
||||
{
|
||||
if(audioWithMetadata.hasMetadata())
|
||||
{
|
||||
Map<String,String> metadata = audioWithMetadata.getMetadata();
|
||||
|
||||
if(metadata.containsKey(METADATA_TYPE_DTMF))
|
||||
{
|
||||
String dtmf = metadata.get(METADATA_TYPE_DTMF);
|
||||
|
||||
if(dtmf != null)
|
||||
{
|
||||
if(mDtmfMetadataProcessor == null)
|
||||
{
|
||||
mDtmfMetadataProcessor = new MetadataProcessor();
|
||||
}
|
||||
|
||||
List<String> dtmfTones = mDtmfMetadataProcessor.process(dtmf);
|
||||
broadcast(P25DtmfIdentifier.create(dtmfTones));
|
||||
}
|
||||
}
|
||||
else if(metadata.containsKey(METADATA_TYPE_KNOX))
|
||||
{
|
||||
String knox = metadata.get(METADATA_TYPE_KNOX);
|
||||
|
||||
if(knox != null)
|
||||
{
|
||||
if(mKnoxMetadataProcessor == null)
|
||||
{
|
||||
mKnoxMetadataProcessor = new MetadataProcessor();
|
||||
}
|
||||
|
||||
List<String> knoxTones = mKnoxMetadataProcessor.process(knox);
|
||||
broadcast(P25KnoxIdentifier.create(knoxTones));
|
||||
}
|
||||
}
|
||||
else if(metadata.containsKey(METADATA_TYPE_TONE))
|
||||
{
|
||||
String tone = metadata.get(METADATA_TYPE_TONE);
|
||||
|
||||
if(tone != null)
|
||||
{
|
||||
if(mToneMetadataProcessor == null)
|
||||
{
|
||||
mToneMetadataProcessor = new MetadataProcessor();
|
||||
}
|
||||
|
||||
List<String> tones = mToneMetadataProcessor.process(tone);
|
||||
broadcast(P25ToneIdentifier.create(tones));
|
||||
}
|
||||
}
|
||||
else if(metadata.containsKey(METADATA_TYPE_CALL_PROGRESS))
|
||||
{
|
||||
String callProgressTone = metadata.get(METADATA_TYPE_CALL_PROGRESS);
|
||||
|
||||
if(callProgressTone != null)
|
||||
{
|
||||
if(mCallProcessMetadataProcessor == null)
|
||||
{
|
||||
mCallProcessMetadataProcessor = new MetadataProcessor();
|
||||
}
|
||||
|
||||
List<String> tones = mCallProcessMetadataProcessor.process(callProgressTone);
|
||||
broadcast(P25CallProgressIdentifier.create(tones));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mDtmfMetadataProcessor != null)
|
||||
{
|
||||
mDtmfMetadataProcessor.noMetadata();
|
||||
}
|
||||
if(mKnoxMetadataProcessor != null)
|
||||
{
|
||||
mKnoxMetadataProcessor.noMetadata();
|
||||
}
|
||||
if(mCallProcessMetadataProcessor != null)
|
||||
{
|
||||
mCallProcessMetadataProcessor.noMetadata();
|
||||
}
|
||||
if(mToneMetadataProcessor != null)
|
||||
{
|
||||
mToneMetadataProcessor.noMetadata();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void broadcast(Identifier identifier)
|
||||
{
|
||||
if(mIdentifierUpdateNotificationListener != null)
|
||||
{
|
||||
mIdentifierUpdateNotificationListener.receive(new IdentifierUpdateNotification(identifier,
|
||||
IdentifierUpdateNotification.Operation.ADD, getTimeslot()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifierUpdateListener(Listener<IdentifierUpdateNotification> listener)
|
||||
{
|
||||
mIdentifierUpdateNotificationListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeIdentifierUpdateListener()
|
||||
{
|
||||
mIdentifierUpdateNotificationListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes metadata string values to provide a de-duplicated list of metadata values.
|
||||
*
|
||||
* This is necessary for metadata such as DTMF where a tone can span multiple 20ms voice frames but is intended
|
||||
* to be represented as a single tone. An empty (no-metadata) frame causes the repeat checker to stop and allow
|
||||
* the next metadata value to be added to the list.
|
||||
*/
|
||||
public class MetadataProcessor
|
||||
{
|
||||
private List<String> mValues = new ArrayList<>();
|
||||
private String mLastInput;
|
||||
|
||||
public List<String> process(String value)
|
||||
{
|
||||
if(value != null)
|
||||
{
|
||||
if(mLastInput != null && mLastInput.equalsIgnoreCase(value))
|
||||
{
|
||||
//Suppress the repeat and return the current value
|
||||
return mValues;
|
||||
}
|
||||
else
|
||||
{
|
||||
mLastInput = value;
|
||||
mValues.add(value);
|
||||
return mValues;
|
||||
}
|
||||
}
|
||||
|
||||
return mValues;
|
||||
}
|
||||
|
||||
public void noMetadata()
|
||||
{
|
||||
mLastInput = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for squelch state to process end of call actions. At call end the encrypted call state established
|
||||
* flag is reset so that the encrypted audio state for the next call can be properly detected and we send an
|
||||
* END audio packet so that downstream processors like the audio recorder can properly close out a call sequence.
|
||||
*/
|
||||
public class SquelchStateListener implements Listener<SquelchStateEvent>
|
||||
{
|
||||
@Override
|
||||
public void receive(SquelchStateEvent event)
|
||||
{
|
||||
if(event.getTimeslot() == getTimeslot() && event.getSquelchState() == SquelchState.SQUELCH)
|
||||
{
|
||||
if(hasAudioPacketListener())
|
||||
{
|
||||
ReusableAudioPacket endAudioPacket = getAudioPacketQueue().getEndAudioBuffer();
|
||||
endAudioPacket.resetAttributes();
|
||||
endAudioPacket.setAudioChannelId(getAudioChannelId());
|
||||
endAudioPacket.setIdentifierCollection(getIdentifierCollection().copyOf());
|
||||
endAudioPacket.incrementUserCount();
|
||||
getAudioPacketListener().receive(endAudioPacket);
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * 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.audio;
|
||||
|
||||
|
||||
import io.github.dsheirer.audio.codec.mbe.MBECallSequence;
|
||||
import io.github.dsheirer.audio.codec.mbe.MBECallSequenceRecorder;
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.P25P2Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.EndPushToTalk;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelUserAbbreviated;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelUserExtended;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.PushToTalk;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.TelephoneInterconnectVoiceChannelUser;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitVoiceChannelUserAbbreviated;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitVoiceChannelUserExtended;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.timeslot.AbstractVoiceTimeslot;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* P25 Phase 2 AMBE Frame recorder generates P25 call sequence recordings containing JSON representations of audio
|
||||
* frames, optional encryption and call identifiers.
|
||||
*/
|
||||
public class P25P2CallSequenceRecorder extends MBECallSequenceRecorder
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P2CallSequenceRecorder.class);
|
||||
|
||||
private static final String PROTOCOL = "APCO25-PHASE2";
|
||||
|
||||
private TimeslotCallSequenceProcessor mTimeslot0Processor = new TimeslotCallSequenceProcessor(0);
|
||||
private TimeslotCallSequenceProcessor mTimeslot1Processor = new TimeslotCallSequenceProcessor(1);
|
||||
|
||||
/**
|
||||
* Constructs a P25-Phase2 MBE call sequence recorder.
|
||||
*
|
||||
* @param userPreferences to obtain the recording directory
|
||||
* @param channelFrequency for the channel to record
|
||||
*/
|
||||
public P25P2CallSequenceRecorder(UserPreferences userPreferences, long channelFrequency, String system, String site)
|
||||
{
|
||||
super(userPreferences, channelFrequency, system, site);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops and flushes any partial frame sequence from the processors
|
||||
*/
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
mTimeslot0Processor.flush();
|
||||
mTimeslot1Processor.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary message interface for receiving frames and metadata messages to record
|
||||
*/
|
||||
@Override
|
||||
public void receive(IMessage message)
|
||||
{
|
||||
if(message instanceof P25P2Message)
|
||||
{
|
||||
P25P2Message p25p2 = (P25P2Message)message;
|
||||
|
||||
if(p25p2.isValid())
|
||||
{
|
||||
switch(p25p2.getTimeslot())
|
||||
{
|
||||
case 0:
|
||||
mTimeslot0Processor.process(p25p2);
|
||||
break;
|
||||
case 1:
|
||||
mTimeslot1Processor.process(p25p2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Timeslot call sequence processor
|
||||
*/
|
||||
class TimeslotCallSequenceProcessor
|
||||
{
|
||||
private int mTimeslot;
|
||||
private MBECallSequence mCallSequence;
|
||||
|
||||
/**
|
||||
* Constructs a processor for the specified channel number / timeslot
|
||||
* @param timeslot
|
||||
*/
|
||||
public TimeslotCallSequenceProcessor(int timeslot)
|
||||
{
|
||||
mTimeslot = timeslot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timeslot for this processor
|
||||
*/
|
||||
public int getTimeslot()
|
||||
{
|
||||
return mTimeslot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes any partial call sequence
|
||||
*/
|
||||
public void flush()
|
||||
{
|
||||
if(mCallSequence != null)
|
||||
{
|
||||
writeCallSequence(mCallSequence, "TS" + getTimeslot());
|
||||
mCallSequence = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes any P25 Phase 2 message
|
||||
*/
|
||||
public void process(P25P2Message message)
|
||||
{
|
||||
if(message instanceof AbstractVoiceTimeslot)
|
||||
{
|
||||
process((AbstractVoiceTimeslot)message);
|
||||
}
|
||||
else if(message instanceof MacMessage)
|
||||
{
|
||||
process((MacMessage)message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes Voice timeslots
|
||||
*/
|
||||
private void process(AbstractVoiceTimeslot voiceTimeslot)
|
||||
{
|
||||
if(mCallSequence == null)
|
||||
{
|
||||
mCallSequence = new MBECallSequence(PROTOCOL);
|
||||
}
|
||||
|
||||
List<BinaryMessage> voiceFrames = voiceTimeslot.getVoiceFrames();
|
||||
|
||||
long baseTimestamp = voiceTimeslot.getTimestamp();
|
||||
|
||||
for(BinaryMessage frame : voiceFrames)
|
||||
{
|
||||
mCallSequence.addVoiceFrame(baseTimestamp, frame.toHexString());
|
||||
|
||||
//Voice frames are 20 milliseconds each, so we increment the timestamp by 20 for each one
|
||||
baseTimestamp += 20;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a MAC message
|
||||
*/
|
||||
private void process(MacMessage macMessage)
|
||||
{
|
||||
switch(macMessage.getMacPduType())
|
||||
{
|
||||
case MAC_1_PTT:
|
||||
case MAC_4_ACTIVE:
|
||||
process(macMessage.getMacStructure(), true);
|
||||
break;
|
||||
case MAC_2_END_PTT:
|
||||
case MAC_6_HANGTIME:
|
||||
process(macMessage.getMacStructure(), false);
|
||||
break;
|
||||
case MAC_3_IDLE:
|
||||
flush();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a mac structure message to obtain from/to identifiers and to optionally close the call sequence
|
||||
* when the MAC pdu indicates that the call sequence is no longer active
|
||||
*
|
||||
* @param mac
|
||||
* @param isActive
|
||||
*/
|
||||
private void process(MacStructure mac, boolean isActive)
|
||||
{
|
||||
if(mCallSequence == null && isActive)
|
||||
{
|
||||
mCallSequence = new MBECallSequence(PROTOCOL);
|
||||
}
|
||||
|
||||
if(mCallSequence != null)
|
||||
{
|
||||
switch(mac.getOpcode())
|
||||
{
|
||||
case PUSH_TO_TALK:
|
||||
if(mac instanceof PushToTalk)
|
||||
{
|
||||
PushToTalk ptt = (PushToTalk)mac;
|
||||
|
||||
if(mCallSequence == null)
|
||||
{
|
||||
mCallSequence = new MBECallSequence(PROTOCOL);
|
||||
}
|
||||
mCallSequence.setFromIdentifier(ptt.getSourceAddress().toString());
|
||||
mCallSequence.setToIdentifier(ptt.getGroupAddress().toString());
|
||||
|
||||
if(ptt.isEncrypted())
|
||||
{
|
||||
mCallSequence.setEncrypted(true);
|
||||
mCallSequence.setEncryptionSyncParameters(ptt.getEncryptionSyncParameters());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Expected push-to-talk structure but found: " + mac.getClass());
|
||||
}
|
||||
break;
|
||||
case END_PUSH_TO_TALK:
|
||||
if(mac instanceof EndPushToTalk)
|
||||
{
|
||||
EndPushToTalk eptt = (EndPushToTalk)mac;
|
||||
|
||||
String source = eptt.getSourceAddress().toString();
|
||||
|
||||
if(source != null && !source.contentEquals("16777215"))
|
||||
{
|
||||
mCallSequence.setFromIdentifier(source);
|
||||
}
|
||||
mCallSequence.setToIdentifier(eptt.getGroupAddress().toString());
|
||||
writeCallSequence(mCallSequence, "TS" + getTimeslot());
|
||||
mCallSequence = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Expected End push-to-talk structure but found: " + mac.getClass());
|
||||
}
|
||||
break;
|
||||
case TDMA_1_GROUP_VOICE_CHANNEL_USER_ABBREVIATED:
|
||||
if(mac instanceof GroupVoiceChannelUserAbbreviated)
|
||||
{
|
||||
GroupVoiceChannelUserAbbreviated gvcua = (GroupVoiceChannelUserAbbreviated)mac;
|
||||
mCallSequence.setFromIdentifier(gvcua.getSourceAddress().toString());
|
||||
mCallSequence.setToIdentifier(gvcua.getGroupAddress().toString());
|
||||
mCallSequence.setCallType(CALL_TYPE_GROUP);
|
||||
if(gvcua.getServiceOptions().isEncrypted())
|
||||
{
|
||||
mCallSequence.setEncrypted(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Expected group voice channel user abbreviated but found: " + mac.getClass());
|
||||
}
|
||||
break;
|
||||
case TDMA_2_UNIT_TO_UNIT_VOICE_CHANNEL_USER:
|
||||
if(mac instanceof UnitToUnitVoiceChannelUserAbbreviated)
|
||||
{
|
||||
UnitToUnitVoiceChannelUserAbbreviated uuvcua = (UnitToUnitVoiceChannelUserAbbreviated)mac;
|
||||
mCallSequence.setFromIdentifier(uuvcua.getSourceAddress().toString());
|
||||
mCallSequence.setToIdentifier(uuvcua.getTargetAddress().toString());
|
||||
mCallSequence.setCallType(CALL_TYPE_INDIVIDUAL);
|
||||
if(uuvcua.getServiceOptions().isEncrypted())
|
||||
{
|
||||
mCallSequence.setEncrypted(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Expected unit-2-unit voice channel user abbreviated but found: " + mac.getClass());
|
||||
}
|
||||
break;
|
||||
case TDMA_3_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER:
|
||||
if(mac instanceof TelephoneInterconnectVoiceChannelUser)
|
||||
{
|
||||
TelephoneInterconnectVoiceChannelUser tivcu = (TelephoneInterconnectVoiceChannelUser)mac;
|
||||
mCallSequence.setToIdentifier(tivcu.getToOrFromAddress().toString());
|
||||
mCallSequence.setCallType(CALL_TYPE_TELEPHONE_INTERCONNECT);
|
||||
if(tivcu.getServiceOptions().isEncrypted())
|
||||
{
|
||||
mCallSequence.setEncrypted(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Expected telephone interconnect voice channel user abbreviated but found: " + mac.getClass());
|
||||
}
|
||||
break;
|
||||
case TDMA_33_GROUP_VOICE_CHANNEL_USER_EXTENDED:
|
||||
if(mac instanceof GroupVoiceChannelUserExtended)
|
||||
{
|
||||
GroupVoiceChannelUserExtended gvcue = (GroupVoiceChannelUserExtended)mac;
|
||||
mCallSequence.setFromIdentifier(gvcue.getSourceAddress().toString());
|
||||
mCallSequence.setToIdentifier(gvcue.getGroupAddress().toString());
|
||||
mCallSequence.setCallType(CALL_TYPE_GROUP);
|
||||
if(gvcue.getServiceOptions().isEncrypted())
|
||||
{
|
||||
mCallSequence.setEncrypted(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Expected group voice channel user extended but found: " + mac.getClass());
|
||||
}
|
||||
break;
|
||||
case TDMA_34_UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED:
|
||||
if(mac instanceof UnitToUnitVoiceChannelUserExtended)
|
||||
{
|
||||
UnitToUnitVoiceChannelUserExtended uuvcue = (UnitToUnitVoiceChannelUserExtended)mac;
|
||||
mCallSequence.setFromIdentifier(uuvcue.getSourceAddress().toString());
|
||||
mCallSequence.setToIdentifier(uuvcue.getTargetAddress().toString());
|
||||
mCallSequence.setCallType(CALL_TYPE_INDIVIDUAL);
|
||||
if(uuvcue.getServiceOptions().isEncrypted())
|
||||
{
|
||||
mCallSequence.setEncrypted(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.warn("Expected unit-2-unit voice channel user extended but found: " + mac.getClass());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(!isActive)
|
||||
{
|
||||
writeCallSequence(mCallSequence, "TS" + getTimeslot());
|
||||
mCallSequence = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * 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.audio;
|
||||
|
||||
import io.github.dsheirer.audio.codec.mbe.IEncryptionSyncParameters;
|
||||
import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier;
|
||||
|
||||
public class Phase2EncryptionSyncParameters implements IEncryptionSyncParameters
|
||||
{
|
||||
private EncryptionKeyIdentifier mEncryptionKeyIdentifier;
|
||||
private String mMessageIndicator;
|
||||
|
||||
public Phase2EncryptionSyncParameters(EncryptionKeyIdentifier encryptionKeyIdentifier, String messageIndicator)
|
||||
{
|
||||
mEncryptionKeyIdentifier = encryptionKeyIdentifier;
|
||||
mMessageIndicator = messageIndicator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EncryptionKeyIdentifier getEncryptionKey()
|
||||
{
|
||||
return mEncryptionKeyIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessageIndicator()
|
||||
{
|
||||
return mMessageIndicator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* 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.audio;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||
|
||||
/**
|
||||
* Voice frame using hexadecimal representation of the transmitted voice and ecc bits
|
||||
*/
|
||||
@JsonRootName(value = "frame")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonPropertyOrder({"encryption_algorithm", "encryption_key_id", "encryption_mi", "time", "hex"})
|
||||
public class VoiceFrame
|
||||
{
|
||||
private long mTimestamp;
|
||||
private String mFrame;
|
||||
private Integer mAlgorithm;
|
||||
private Integer mKeyId;
|
||||
private String mMessageIndicator;
|
||||
|
||||
public VoiceFrame()
|
||||
{
|
||||
//no-arg constructor for faster jackson deserialization
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an unencrypted voice frame
|
||||
*
|
||||
* @param timestamp the frame was transmitted
|
||||
* @param frame with voice and ecc bits
|
||||
*/
|
||||
public VoiceFrame(long timestamp, String frame)
|
||||
{
|
||||
mTimestamp = timestamp;
|
||||
mFrame = frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an encrypted voice frame
|
||||
*
|
||||
* @param timestamp the message was transmitted
|
||||
* @param frame of hexadecimal values
|
||||
* @param algorithm used to encrypt the voice frame
|
||||
* @param keyid used to encrypt the voice frame
|
||||
* @param messageIndicator for the key generator fill
|
||||
*/
|
||||
public VoiceFrame(long timestamp, String frame, int algorithm, int keyid, String messageIndicator)
|
||||
{
|
||||
this(timestamp, frame);
|
||||
mAlgorithm = algorithm;
|
||||
mKeyId = keyid;
|
||||
mMessageIndicator = messageIndicator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamp the frame was transmitted
|
||||
*
|
||||
* @return timestamp in milliseconds since epoch (1970)
|
||||
*/
|
||||
@JsonProperty("time")
|
||||
public long getTimestamp()
|
||||
{
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp)
|
||||
{
|
||||
mTimestamp = timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmitted voice frame and ecc bits in hexadecimal
|
||||
*/
|
||||
@JsonProperty("hex")
|
||||
public String getFrame()
|
||||
{
|
||||
return mFrame;
|
||||
}
|
||||
|
||||
public void setFrame(String frame)
|
||||
{
|
||||
mFrame = frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio frame bytes
|
||||
* @return frame bytes or null
|
||||
*/
|
||||
@JsonIgnore
|
||||
public byte[] getFrameBytes()
|
||||
{
|
||||
if(mFrame != null)
|
||||
{
|
||||
byte[] bytes = new byte[mFrame.length() / 2];
|
||||
for(int x = 0; x < mFrame.length(); x += 2)
|
||||
{
|
||||
String hex = mFrame.substring(x, x + 2);
|
||||
bytes[x / 2] = (byte) (0xFF & Integer.parseInt(hex, 16));
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Algorithm identifier numeric value
|
||||
*
|
||||
* @return algorithm id
|
||||
*/
|
||||
@JsonProperty("encryption_algorithm")
|
||||
public Integer getAlgorithm()
|
||||
{
|
||||
return mAlgorithm;
|
||||
}
|
||||
|
||||
public void setAlgorithm(int algorithm)
|
||||
{
|
||||
mAlgorithm = algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Key identifier
|
||||
*
|
||||
* @return key id
|
||||
*/
|
||||
@JsonProperty("encryption_key_id")
|
||||
public Integer getKeyId()
|
||||
{
|
||||
return mKeyId;
|
||||
}
|
||||
|
||||
public void setKeyId(int keyId)
|
||||
{
|
||||
mKeyId = keyId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Key generator fill values
|
||||
*
|
||||
* @return message indicator
|
||||
*/
|
||||
@JsonProperty("encryption_mi")
|
||||
public String getMessageIndicator()
|
||||
{
|
||||
return mMessageIndicator;
|
||||
}
|
||||
|
||||
public void setMessageIndicator(String messageIndicator)
|
||||
{
|
||||
mMessageIndicator = messageIndicator;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.identifier.channel;
|
||||
|
||||
@@ -24,7 +26,7 @@ import io.github.dsheirer.identifier.Form;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.IdentifierClass;
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.module.decode.p25.message.IFrequencyBand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
/**
|
||||
@@ -92,6 +94,15 @@ public class APCO25Channel extends Identifier<P25Channel> implements IChannelDes
|
||||
return getValue().getUplinkFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Timeslot for this channel
|
||||
* @return timeslot
|
||||
*/
|
||||
public int getTimeslot()
|
||||
{
|
||||
return getValue().getTimeslot();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new APCO-25 identifier
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.identifier.channel;
|
||||
|
||||
import io.github.dsheirer.channel.IChannelDescriptor;
|
||||
import io.github.dsheirer.module.decode.p25.message.IFrequencyBand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
import java.util.Objects;
|
||||
@@ -131,7 +133,7 @@ public class P25Channel implements IChannelDescriptor
|
||||
return mFrequencyBand.getTimeslotCount();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -145,6 +147,38 @@ public class P25Channel implements IChannelDescriptor
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timeslot for a TDMA channel
|
||||
* @return timeslot or 0 if the channel is not a TDMA channel
|
||||
*/
|
||||
public int getTimeslot()
|
||||
{
|
||||
if(isTDMAChannel())
|
||||
{
|
||||
return getDownlinkChannelNumber() % getTimeslotCount();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical channel number. For Phase 1 channels this is the downlink channel number. For Phase 2 channels, this
|
||||
* is the channel number without the timeslot specifier.
|
||||
*/
|
||||
public int getDownlinkLogicalChannelNumber()
|
||||
{
|
||||
return getDownlinkChannelNumber() / getTimeslotCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical channel number. For Phase 1 channels this is the uplink channel number. For Phase 2 channels, this
|
||||
* is the channel number without the timeslot specifier.
|
||||
*/
|
||||
public int getUplinkLogicalChannelNumber()
|
||||
{
|
||||
return getUplinkChannelNumber() / getTimeslotCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatted channel number
|
||||
*/
|
||||
@@ -152,19 +186,26 @@ public class P25Channel implements IChannelDescriptor
|
||||
{
|
||||
if(getDownlinkBandIdentifier() == getUplinkBandIdentifier() && getDownlinkChannelNumber() == getUplinkChannelNumber())
|
||||
{
|
||||
return getDownlinkBandIdentifier() + "-" + getDownlinkChannelNumber();
|
||||
return getDownlinkBandIdentifier() + "-" + (getDownlinkLogicalChannelNumber());
|
||||
}
|
||||
else if(hasUplinkChannel())
|
||||
{
|
||||
return getDownlinkBandIdentifier() + "-" + getDownlinkChannelNumber() + "/" +
|
||||
getUplinkBandIdentifier() + "-" + getUplinkChannelNumber();
|
||||
return getDownlinkBandIdentifier() + "-" + (getDownlinkLogicalChannelNumber()) + "/" +
|
||||
getUplinkBandIdentifier() + "-" + (getUplinkLogicalChannelNumber());
|
||||
}
|
||||
else
|
||||
{
|
||||
return getDownlinkBandIdentifier() + "-" + getDownlinkChannelNumber() + "/-----";
|
||||
return getDownlinkBandIdentifier() + "-" + (getDownlinkLogicalChannelNumber()) + "/-----";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Designates channel equality as having the same band identifier and channel number.
|
||||
*
|
||||
* Note: Phase 2 channels also specify timeslot for a channel, but timeslot is not considered for equality.
|
||||
* @param o other object
|
||||
* @return true if both instances are P25 channels in the same band and channel number
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
@@ -172,18 +213,21 @@ public class P25Channel implements IChannelDescriptor
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(o == null || getClass() != o.getClass())
|
||||
if(o == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!(o instanceof P25Channel))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
P25Channel that = (P25Channel)o;
|
||||
return mBandIdentifier == that.mBandIdentifier &&
|
||||
mChannelNumber == that.mChannelNumber;
|
||||
return mBandIdentifier == that.mBandIdentifier && getDownlinkLogicalChannelNumber() == that.getDownlinkLogicalChannelNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(mBandIdentifier, mChannelNumber);
|
||||
return Objects.hash(mBandIdentifier, getDownlinkLogicalChannelNumber());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.p25.identifier.channel;
|
||||
|
||||
import io.github.dsheirer.module.decode.p25.message.IFrequencyBand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
|
||||
|
||||
public class P25ExplicitChannel extends P25Channel implements Comparable<P25Channel>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * 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.identifier.channel;
|
||||
|
||||
/**
|
||||
* P25 Phase II Channel. Note: this channel is hard-coded for 2 timeslots, independent of the band identifier.
|
||||
*/
|
||||
public class P25P2Channel extends P25Channel
|
||||
{
|
||||
public P25P2Channel(int bandIdentifier, int channelNumber)
|
||||
{
|
||||
super(bandIdentifier, channelNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeslotCount()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTDMAChannel()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * 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.identifier.channel;
|
||||
|
||||
/**
|
||||
* Explicit P25 Phase 2 channel.
|
||||
*/
|
||||
public class P25P2ExplicitChannel extends P25ExplicitChannel
|
||||
{
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param downlinkBandIdentifier
|
||||
* @param downlinkChannelNumber
|
||||
* @param uplinkBandIdentifier
|
||||
* @param uplinkChannelNumber
|
||||
*/
|
||||
public P25P2ExplicitChannel(int downlinkBandIdentifier, int downlinkChannelNumber, int uplinkBandIdentifier, int uplinkChannelNumber)
|
||||
{
|
||||
super(downlinkBandIdentifier, downlinkChannelNumber, uplinkBandIdentifier, uplinkChannelNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeslotCount()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTDMAChannel()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +1,78 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.identifier.encryption;
|
||||
|
||||
import io.github.dsheirer.identifier.Form;
|
||||
import io.github.dsheirer.identifier.IdentifierClass;
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.encryption.EncryptionKey;
|
||||
import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
import io.github.dsheirer.module.decode.p25.reference.Encryption;
|
||||
|
||||
public class APCO25EncryptionKey extends EncryptionKeyIdentifier
|
||||
public class APCO25EncryptionKey extends EncryptionKey
|
||||
{
|
||||
public APCO25EncryptionKey(EncryptionKey encryptionKey)
|
||||
public APCO25EncryptionKey(int algorithm, int keyId)
|
||||
{
|
||||
super(encryptionKey, IdentifierClass.NETWORK, Form.ENCRYPTION_KEY, Role.BROADCAST);
|
||||
super(algorithm, keyId);
|
||||
}
|
||||
|
||||
public Encryption getEncryptionAlgorithm()
|
||||
{
|
||||
return Encryption.fromValue(getAlgorithm());
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if(isEncrypted())
|
||||
{
|
||||
Encryption encryption = getEncryptionAlgorithm();
|
||||
|
||||
if(encryption == Encryption.UNKNOWN)
|
||||
{
|
||||
sb.append("ALGORITHM ID:").append(getAlgorithm());
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("ENCRYPTION:").append(getEncryptionAlgorithm());
|
||||
}
|
||||
|
||||
sb.append(" KEY:").append(getKey());
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("NO ENCRYPTION");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Protocol getProtocol()
|
||||
public boolean isEncrypted()
|
||||
{
|
||||
return Protocol.APCO25;
|
||||
return getEncryptionAlgorithm() != Encryption.UNENCRYPTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new APCO-25 encryption algorithm
|
||||
*/
|
||||
public static APCO25EncryptionKey create(int alogorithm, int keyId)
|
||||
public static APCO25EncryptionKey create(int algorithm, int keyId)
|
||||
{
|
||||
return new APCO25EncryptionKey(new EncryptionKey(alogorithm, keyId));
|
||||
return new APCO25EncryptionKey(algorithm, keyId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * 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.identifier.talkgroup;
|
||||
|
||||
import io.github.dsheirer.identifier.Form;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.IdentifierClass;
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.talkgroup.FullyQualifiedIdentifier;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
/**
|
||||
* Fully Qualified Radio Identifier (talkgroup) that includes WACN, System, and Radio Address.
|
||||
*/
|
||||
public class APCO25FullyQualifiedIdentifier extends Identifier<FullyQualifiedIdentifier>
|
||||
{
|
||||
public APCO25FullyQualifiedIdentifier(FullyQualifiedIdentifier value, Role role)
|
||||
{
|
||||
super(value, IdentifierClass.USER, Form.FULLY_QUALIFIED_IDENTIFIER, role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Protocol getProtocol()
|
||||
{
|
||||
return Protocol.APCO25;
|
||||
}
|
||||
|
||||
public static APCO25FullyQualifiedIdentifier createFrom(int wacn, int system, int id)
|
||||
{
|
||||
return new APCO25FullyQualifiedIdentifier(FullyQualifiedIdentifier.create(wacn, system, id), Role.FROM);
|
||||
}
|
||||
|
||||
public static APCO25FullyQualifiedIdentifier createTo(int wacn, int system, int id)
|
||||
{
|
||||
return new APCO25FullyQualifiedIdentifier(FullyQualifiedIdentifier.create(wacn, system, id), Role.TO);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message;
|
||||
|
||||
import io.github.dsheirer.channel.IChannelDescriptor;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
|
||||
/**
|
||||
* Interface for adjacent site (ie neighbor) messages
|
||||
*/
|
||||
public interface IAdjacentSite
|
||||
{
|
||||
String getUniqueID();
|
||||
|
||||
Identifier getRFSSId();
|
||||
|
||||
Identifier getSystemID();
|
||||
|
||||
Identifier getSiteID();
|
||||
|
||||
Identifier getLRAId();
|
||||
|
||||
String getSystemServiceClass();
|
||||
|
||||
IChannelDescriptor getChannel();
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.hdu.HDUMessage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class HDUMessageFilter extends Filter<IMessage>
|
||||
{
|
||||
public HDUMessageFilter()
|
||||
{
|
||||
super("Header Data Unit");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passes(IMessage message)
|
||||
{
|
||||
return mEnabled && canProcess(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(IMessage message)
|
||||
{
|
||||
return message instanceof HDUMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FilterElement<?>> getFilterElements()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.ldu.LDUMessage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class LDUMessageFilter extends Filter<IMessage>
|
||||
{
|
||||
public LDUMessageFilter()
|
||||
{
|
||||
super("Link Data Unit");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passes(IMessage message)
|
||||
{
|
||||
return mEnabled && canProcess(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(IMessage message)
|
||||
{
|
||||
return message instanceof LDUMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FilterElement<?>> getFilterElements()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.FilterSet;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.message.SyncLossMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.P25Message;
|
||||
|
||||
public class P25MessageFilterSet extends FilterSet<IMessage>
|
||||
{
|
||||
public P25MessageFilterSet()
|
||||
{
|
||||
super("P25 Message Filter");
|
||||
|
||||
addFilter(new AMBTCMessageFilter());
|
||||
addFilter(new HDUMessageFilter());
|
||||
addFilter(new IPPacketMessageFilter());
|
||||
addFilter(new LDUMessageFilter());
|
||||
addFilter(new PDUMessageFilter());
|
||||
addFilter(new SNDCPMessageFilter());
|
||||
addFilter(new SyncLossMessageFilter());
|
||||
addFilter(new TDUMessageFilter());
|
||||
addFilter(new TDULCMessageFilter());
|
||||
addFilter(new TSBKMessageFilterSet());
|
||||
addFilter(new UMBTCMessageFilter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(IMessage message)
|
||||
{
|
||||
return message instanceof P25Message || message instanceof SyncLossMessage;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.tdu.TDULinkControlMessage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TDULCMessageFilter extends Filter<IMessage>
|
||||
{
|
||||
public TDULCMessageFilter()
|
||||
{
|
||||
super("TDU Terminator Data Unit with Link Control");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passes(IMessage message)
|
||||
{
|
||||
return mEnabled && canProcess(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(IMessage message)
|
||||
{
|
||||
return message instanceof TDULinkControlMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FilterElement<?>> getFilterElements()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.tdu.TDUMessage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TDUMessageFilter extends Filter<IMessage>
|
||||
{
|
||||
public TDUMessageFilter()
|
||||
{
|
||||
super("TDU Terminator Data Unit");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passes(IMessage message)
|
||||
{
|
||||
return mEnabled && canProcess(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(IMessage message)
|
||||
{
|
||||
return message instanceof TDUMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FilterElement<?>> getFilterElements()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.lc;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Unknown link control word.
|
||||
*/
|
||||
public class UnknownLinkControlWord extends LinkControlWord
|
||||
{
|
||||
/**
|
||||
* Constructs a Link Control Word from the binary message sequence.
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
public UnknownLinkControlWord(BinaryMessage message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getMessageStub());
|
||||
sb.append(" UNKNOWN/UNRECOGNIZED OPCODE");
|
||||
sb.append(" MSG:").append(getMessage().toHexString());
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.pdu;
|
||||
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.p25.message.P25Message;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class PDUSequenceMessage extends P25Message
|
||||
{
|
||||
private PDUSequence mPDUSequence;
|
||||
|
||||
public PDUSequenceMessage(PDUSequence PDUSequence, int nac, long timestamp)
|
||||
{
|
||||
super(null, nac, timestamp);
|
||||
mPDUSequence = PDUSequence;
|
||||
}
|
||||
|
||||
public PDUSequence getPDUSequence()
|
||||
{
|
||||
return mPDUSequence;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getPDUSequence().toString());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataUnitID getDUID()
|
||||
{
|
||||
return DataUnitID.PACKET_DATA_UNIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.tsbk;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
import io.github.dsheirer.module.decode.p25.reference.Direction;
|
||||
|
||||
/**
|
||||
* P25 Inbound (ISP) TSBK Message
|
||||
*/
|
||||
public abstract class ISPMessage extends TSBKMessage
|
||||
{
|
||||
/**
|
||||
* Constructs an inbound (ISP) TSBK from the binary message sequence.
|
||||
*
|
||||
* @param dataUnitID TSBK1/2/3
|
||||
* @param message binary sequence
|
||||
* @param nac decoded from the NID
|
||||
* @param timestamp for the message
|
||||
*/
|
||||
public ISPMessage(DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestamp)
|
||||
{
|
||||
super(dataUnitID, message, nac, timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Direction getDirection()
|
||||
{
|
||||
return Direction.INBOUND;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.tsbk;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
import io.github.dsheirer.module.decode.p25.reference.Direction;
|
||||
|
||||
/**
|
||||
* P25 Outbound (OSP) TSBK Message
|
||||
*/
|
||||
public abstract class OSPMessage extends TSBKMessage
|
||||
{
|
||||
/**
|
||||
* Constructs an outbound (OSP) TSBK from the binary message sequence.
|
||||
*
|
||||
* @param dataUnitID TSBK1/2/3
|
||||
* @param message binary sequence
|
||||
* @param nac decoded from the NID
|
||||
* @param timestamp for the message
|
||||
*/
|
||||
public OSPMessage(DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestamp)
|
||||
{
|
||||
super(dataUnitID, message, nac, timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Direction getDirection()
|
||||
{
|
||||
return Direction.OUTBOUND;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Unknown/Unrecognized opcode message.
|
||||
*/
|
||||
public class UnknownISPMessage extends ISPMessage
|
||||
{
|
||||
/**
|
||||
* Constructs a TSBK from the binary message sequence.
|
||||
*/
|
||||
public UnknownISPMessage(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp)
|
||||
{
|
||||
super(dataUnitId, message, nac, timestamp);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getMessageStub());
|
||||
sb.append(" **UNRECOGNIZED ISP OPCODE**");
|
||||
sb.append(" MSG:").append(getMessage().toHexString());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Unknown/Unrecognized opcode message.
|
||||
*/
|
||||
public class UnknownOSPMessage extends OSPMessage
|
||||
{
|
||||
/**
|
||||
* Constructs a TSBK from the binary message sequence.
|
||||
*/
|
||||
public UnknownOSPMessage(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp)
|
||||
{
|
||||
super(dataUnitId, message, nac, timestamp);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getMessageStub());
|
||||
sb.append(" **UNRECOGNIZED OSP OPCODE**");
|
||||
sb.append(" MSG:").append(getMessage().toHexString());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.vselp;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.p25.message.P25Message;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class VSELP1Message extends P25Message
|
||||
{
|
||||
/**
|
||||
* Motorola VSELP audio message 1 - not implemented.
|
||||
*/
|
||||
public VSELP1Message(CorrectedBinaryMessage message, int nac, long timestamp)
|
||||
{
|
||||
super(message, nac, timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getMessageStub());
|
||||
sb.append(" MSG:").append(getMessage().toHexString());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataUnitID getDUID()
|
||||
{
|
||||
return DataUnitID.VSELP1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,20 +18,18 @@
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
package io.github.dsheirer.module.decode.p25.phase1;
|
||||
|
||||
import io.github.dsheirer.module.decode.p25.message.P25Message;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
|
||||
/**
|
||||
* Decoded metadata for an APCO25 channel
|
||||
*/
|
||||
public class P25Metadata implements Listener<P25Message>
|
||||
public interface C4FMFrameListener
|
||||
{
|
||||
/**
|
||||
* Listener interface to receive the output of the C4FMMessageFramer.
|
||||
*
|
||||
* @param buffer - framed message without the sync pattern
|
||||
* @param inverted - flag indicating if the message was received inverted
|
||||
*/
|
||||
public void receive( BinaryMessage buffer, boolean inverted );
|
||||
|
||||
@Override
|
||||
public void receive(P25Message p25Message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,24 @@
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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.dsp.symbol.Dibit;
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
@@ -1,4 +1,24 @@
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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.dsp.gain.DirectGainControl;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
@@ -1,21 +1,23 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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 free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
* 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 com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
@@ -26,7 +28,7 @@ import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
|
||||
|
||||
public class DecodeConfigP25Phase1 extends DecodeConfiguration
|
||||
{
|
||||
private P25DecoderLSM.Modulation mModulation = P25Decoder.Modulation.C4FM;
|
||||
private P25P1Decoder.Modulation mModulation = P25P1Decoder.Modulation.C4FM;
|
||||
|
||||
private int mCallTimeout = 1;
|
||||
private int mTrafficChannelPoolSize = TRAFFIC_CHANNEL_LIMIT_DEFAULT;
|
||||
@@ -43,12 +45,12 @@ public class DecodeConfigP25Phase1 extends DecodeConfiguration
|
||||
}
|
||||
|
||||
@JacksonXmlProperty(isAttribute = true, localName = "modulation")
|
||||
public P25DecoderLSM.Modulation getModulation()
|
||||
public P25P1Decoder.Modulation getModulation()
|
||||
{
|
||||
return mModulation;
|
||||
}
|
||||
|
||||
public void setModulation(P25DecoderLSM.Modulation modulation)
|
||||
public void setModulation(P25P1Decoder.Modulation modulation)
|
||||
{
|
||||
mModulation = modulation;
|
||||
}
|
||||
@@ -1,27 +1,29 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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 free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Listener interface to be notified each time a P25 sync pattern and data unit has been detected
|
||||
* and the data unit is correct after error detection and correction and/or when the sync has been lost.
|
||||
*/
|
||||
public interface IDataUnitDetectListener
|
||||
public interface IP25P1DataUnitDetectListener
|
||||
{
|
||||
/**
|
||||
* Indicates that a P25 sync has been detected and a P25 data unit was successfully decoded.
|
||||
@@ -31,7 +33,7 @@ public interface IDataUnitDetectListener
|
||||
* @param bitErrors detected and corrected from both the sync pattern and the NID.
|
||||
* @param correctedNid bits corrected by the BCH error correction code (temporary until message parsers are updated
|
||||
*/
|
||||
void dataUnitDetected(DataUnitID dataUnitID, int nac, int bitErrors, int discardedDibits, int[] correctedNid);
|
||||
void dataUnitDetected(P25P1DataUnitID dataUnitID, int nac, int bitErrors, int discardedDibits, int[] correctedNid);
|
||||
|
||||
/**
|
||||
* Indicates that sync has been lost on the dibit stream
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,7 +18,7 @@
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
package io.github.dsheirer.module.decode.p25.phase1;
|
||||
|
||||
import io.github.dsheirer.dsp.symbol.Dibit;
|
||||
import io.github.dsheirer.module.decode.p25.reference.Direction;
|
||||
@@ -32,7 +32,7 @@ import io.github.dsheirer.sample.Listener;
|
||||
* Dibits 01 and 11 are used by the repeater.
|
||||
* Dibit 10 is used by both and is ignored by this processor.
|
||||
*/
|
||||
public class P25ChannelStatusProcessor implements Listener<Dibit>
|
||||
public class P25P1ChannelStatusProcessor implements Listener<Dibit>
|
||||
{
|
||||
private int mSubscriberCount = 0;
|
||||
private int mRepeaterCount = 0;
|
||||
@@ -56,26 +56,27 @@ public class P25ChannelStatusProcessor implements Listener<Dibit>
|
||||
|
||||
private void update()
|
||||
{
|
||||
if(mRepeaterCount > mSubscriberCount)
|
||||
{
|
||||
mDirection = Direction.OUTBOUND;
|
||||
|
||||
if(mRepeaterCount == Integer.MAX_VALUE)
|
||||
{
|
||||
mRepeaterCount = 1000;
|
||||
mSubscriberCount = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mDirection = Direction.INBOUND;
|
||||
|
||||
if(mSubscriberCount == Integer.MAX_VALUE)
|
||||
{
|
||||
mSubscriberCount = 1000;
|
||||
mRepeaterCount = 0;
|
||||
}
|
||||
}
|
||||
//This doesn't appear to be reliable and sometimes it fails on Harris systems.
|
||||
// if(mRepeaterCount > mSubscriberCount)
|
||||
// {
|
||||
// mDirection = Direction.OUTBOUND;
|
||||
//
|
||||
// if(mRepeaterCount == Integer.MAX_VALUE)
|
||||
// {
|
||||
// mRepeaterCount = 1000;
|
||||
// mSubscriberCount = 0;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// mDirection = Direction.INBOUND;
|
||||
//
|
||||
// if(mSubscriberCount == Integer.MAX_VALUE)
|
||||
// {
|
||||
// mSubscriberCount = 1000;
|
||||
// mRepeaterCount = 0;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public Direction getDirection()
|
||||
@@ -1,50 +1,53 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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 free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
* 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.dsp.psk.pll.IPhaseLockedLoop;
|
||||
import io.github.dsheirer.dsp.symbol.Dibit;
|
||||
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
|
||||
import io.github.dsheirer.edac.BCH_63_16_11;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class P25DataUnitDetector implements Listener<Dibit>, ISyncDetectListener
|
||||
public class P25P1DataUnitDetector implements Listener<Dibit>, ISyncDetectListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25DataUnitDetector.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P1DataUnitDetector.class);
|
||||
private static final int DATA_UNIT_DIBIT_LENGTH = 57; //56 dibits plus 1 status symbol
|
||||
private static final int SYNC_DIBIT_LENGTH = 24;
|
||||
private static final int MAXIMUM_SYNC_MATCH_BIT_ERRORS = 9;
|
||||
private P25SyncDetector mSyncDetector;
|
||||
private P25P1SyncDetector mSyncDetector;
|
||||
private NIDDelayBuffer mDataUnitBuffer = new NIDDelayBuffer();
|
||||
private DibitDelayBuffer mSyncDelayBuffer = new DibitDelayBuffer(DATA_UNIT_DIBIT_LENGTH - SYNC_DIBIT_LENGTH);
|
||||
private IDataUnitDetectListener mDataUnitDetectListener;
|
||||
private IP25P1DataUnitDetectListener mDataUnitDetectListener;
|
||||
private boolean mInitialSyncTestProcessed = false;
|
||||
private int mDibitsProcessed = 0;
|
||||
private BCH_63_16_11 mNIDDecoder = new BCH_63_16_11();
|
||||
private DataUnitID mPreviousDataUnitId = DataUnitID.TERMINATOR_DATA_UNIT;
|
||||
private P25P1DataUnitID mPreviousDataUnitId = P25P1DataUnitID.TERMINATOR_DATA_UNIT;
|
||||
private int mNIDDetectionCount;
|
||||
|
||||
public P25DataUnitDetector(IDataUnitDetectListener dataUnitDetectListener, IPhaseLockedLoop phaseLockedLoop)
|
||||
public P25P1DataUnitDetector(IP25P1DataUnitDetectListener dataUnitDetectListener, IPhaseLockedLoop phaseLockedLoop)
|
||||
{
|
||||
mDataUnitDetectListener = dataUnitDetectListener;
|
||||
mSyncDetector = new P25SyncDetector(this, phaseLockedLoop);
|
||||
mSyncDetector = new P25P1SyncDetector(this, phaseLockedLoop);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,25 +145,25 @@ public class P25DataUnitDetector implements Listener<Dibit>, ISyncDetectListener
|
||||
(bitErrorCount + nidBitErrorCount), (mDibitsProcessed - DATA_UNIT_DIBIT_LENGTH), correctedNid);
|
||||
}
|
||||
}
|
||||
else if(mPreviousDataUnitId == DataUnitID.LOGICAL_LINK_DATA_UNIT_1)
|
||||
else if(mPreviousDataUnitId == P25P1DataUnitID.LOGICAL_LINK_DATA_UNIT_1)
|
||||
{
|
||||
//We have a good sync match, but the NID didn't pass error control and we're in the middle
|
||||
//of voice call, so treat this message as voice message, but set the previous duid to
|
||||
//terminator so we can end if there isn't a subsequent voice message
|
||||
mDataUnitDetectListener.dataUnitDetected(DataUnitID.LOGICAL_LINK_DATA_UNIT_2, -1,
|
||||
mDataUnitDetectListener.dataUnitDetected(P25P1DataUnitID.LOGICAL_LINK_DATA_UNIT_2, -1,
|
||||
(bitErrorCount + 64), (mDibitsProcessed - DATA_UNIT_DIBIT_LENGTH), new int[63]);
|
||||
|
||||
mPreviousDataUnitId = DataUnitID.TERMINATOR_DATA_UNIT;
|
||||
mPreviousDataUnitId = P25P1DataUnitID.TERMINATOR_DATA_UNIT;
|
||||
}
|
||||
else if(mPreviousDataUnitId == DataUnitID.LOGICAL_LINK_DATA_UNIT_2)
|
||||
else if(mPreviousDataUnitId == P25P1DataUnitID.LOGICAL_LINK_DATA_UNIT_2)
|
||||
{
|
||||
//We have a good sync match, but the NID didn't pass error control and we're in the middle
|
||||
//of voice call, so treat this message as voice message, but set the previous duid to
|
||||
//terminator so we can end if there isn't a subsequent voice message
|
||||
mDataUnitDetectListener.dataUnitDetected(DataUnitID.LOGICAL_LINK_DATA_UNIT_1, -1,
|
||||
mDataUnitDetectListener.dataUnitDetected(P25P1DataUnitID.LOGICAL_LINK_DATA_UNIT_1, -1,
|
||||
(bitErrorCount + 64), (mDibitsProcessed - DATA_UNIT_DIBIT_LENGTH), new int[63]);
|
||||
|
||||
mPreviousDataUnitId = DataUnitID.TERMINATOR_DATA_UNIT;
|
||||
mPreviousDataUnitId = P25P1DataUnitID.TERMINATOR_DATA_UNIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,7 +173,7 @@ public class P25DataUnitDetector implements Listener<Dibit>, ISyncDetectListener
|
||||
* @param nid in reverse bit order
|
||||
* @return
|
||||
*/
|
||||
public DataUnitID getDataUnitID(int[] nid)
|
||||
public P25P1DataUnitID getDataUnitID(int[] nid)
|
||||
{
|
||||
int duid = 0;
|
||||
|
||||
@@ -194,7 +197,7 @@ public class P25DataUnitDetector implements Listener<Dibit>, ISyncDetectListener
|
||||
duid ^= 8;
|
||||
}
|
||||
|
||||
return DataUnitID.fromValue(duid);
|
||||
return P25P1DataUnitID.fromValue(duid);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1,24 +1,28 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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 free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.p25.reference;
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The Data Unit ID (DUID) is part of the Network ID (NID) field and indicates the type of message.
|
||||
*/
|
||||
public enum DataUnitID
|
||||
public enum P25P1DataUnitID
|
||||
{
|
||||
HEADER_DATA_UNIT(0, 648 + 10, true, "HDU "),
|
||||
UNKNOWN_1(1, -1, false, "UNK01"),
|
||||
@@ -53,7 +57,7 @@ public enum DataUnitID
|
||||
private boolean mTrailingStatusDibit;
|
||||
private String mLabel;
|
||||
|
||||
DataUnitID(int value, int length, boolean trailingStatusDibit, String label)
|
||||
P25P1DataUnitID(int value, int length, boolean trailingStatusDibit, String label)
|
||||
{
|
||||
mValue = value;
|
||||
mMessageLength = length;
|
||||
@@ -96,7 +100,7 @@ public enum DataUnitID
|
||||
/**
|
||||
* Lookup the Data Unit ID from an integer value
|
||||
*/
|
||||
public static DataUnitID fromValue(int value)
|
||||
public static P25P1DataUnitID fromValue(int value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
@@ -1,19 +1,25 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
*/
|
||||
package io.github.dsheirer.module.decode.p25.phase1;
|
||||
|
||||
import io.github.dsheirer.dsp.symbol.Dibit;
|
||||
import io.github.dsheirer.dsp.symbol.DibitToByteBufferAssembler;
|
||||
@@ -29,22 +35,22 @@ import io.github.dsheirer.source.ISourceEventListener;
|
||||
import io.github.dsheirer.source.ISourceEventProvider;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
|
||||
public abstract class P25Decoder extends Decoder implements ISourceEventListener, ISourceEventProvider,
|
||||
public abstract class P25P1Decoder extends Decoder implements ISourceEventListener, ISourceEventProvider,
|
||||
IReusableComplexBufferListener, Listener<ReusableComplexBuffer>, IReusableByteBufferProvider
|
||||
{
|
||||
private double mSampleRate;
|
||||
private Broadcaster<Dibit> mDibitBroadcaster = new Broadcaster<>();
|
||||
private DibitToByteBufferAssembler mByteBufferAssembler = new DibitToByteBufferAssembler(300);
|
||||
private P25MessageProcessor mMessageProcessor;
|
||||
private P25P1MessageProcessor mMessageProcessor;
|
||||
private Listener<SourceEvent> mSourceEventListener;
|
||||
private double mSymbolRate;
|
||||
|
||||
public P25Decoder(double symbolRate)
|
||||
public P25P1Decoder(double symbolRate)
|
||||
{
|
||||
mSymbolRate = symbolRate;
|
||||
mMessageProcessor = new P25MessageProcessor();
|
||||
mMessageProcessor = new P25P1MessageProcessor();
|
||||
mMessageProcessor.setMessageListener(getMessageListener());
|
||||
mDibitBroadcaster.addListener(mByteBufferAssembler);
|
||||
getDibitBroadcaster().addListener(mByteBufferAssembler);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +187,7 @@ public abstract class P25Decoder extends Decoder implements ISourceEventListener
|
||||
@Override
|
||||
public Listener<ReusableComplexBuffer> getReusableComplexBufferListener()
|
||||
{
|
||||
return P25Decoder.this;
|
||||
return P25P1Decoder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,7 +214,7 @@ public abstract class P25Decoder extends Decoder implements ISourceEventListener
|
||||
return DecoderType.P25_PHASE1;
|
||||
}
|
||||
|
||||
protected P25MessageProcessor getMessageProcessor()
|
||||
protected P25P1MessageProcessor getMessageProcessor()
|
||||
{
|
||||
return mMessageProcessor;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
package io.github.dsheirer.module.decode.p25.phase1;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
|
||||
@@ -37,16 +37,16 @@ import org.slf4j.LoggerFactory;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class P25DecoderC4FM extends P25Decoder
|
||||
public class P25P1DecoderC4FM extends P25P1Decoder
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25DecoderC4FM.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P1DecoderC4FM.class);
|
||||
|
||||
protected static final float SAMPLE_COUNTER_GAIN = 0.3f;
|
||||
protected InterpolatingSampleBuffer mInterpolatingSampleBuffer;
|
||||
protected DQPSKDecisionDirectedDemodulator mQPSKDemodulator;
|
||||
protected CostasLoop mCostasLoop;
|
||||
protected AdaptivePLLGainMonitor mPLLGainMonitor;
|
||||
protected P25MessageFramer2 mMessageFramer;
|
||||
protected P25P1MessageFramer mMessageFramer;
|
||||
private ComplexFeedForwardGainControl mAGC = new ComplexFeedForwardGainControl(32);
|
||||
private Map<Double,float[]> mBasebandFilters = new HashMap<>();
|
||||
private ComplexFIRFilter2 mBasebandFilter;
|
||||
@@ -55,7 +55,7 @@ public class P25DecoderC4FM extends P25Decoder
|
||||
* P25 Phase 1 - standard C4FM modulation decoder. Uses Differential QPSK decoding with a Costas PLL and a
|
||||
* decision-directed phase and timing error detector.
|
||||
*/
|
||||
public P25DecoderC4FM()
|
||||
public P25P1DecoderC4FM()
|
||||
{
|
||||
super(4800.0);
|
||||
setSampleRate(25000.0);
|
||||
@@ -80,7 +80,7 @@ public class P25DecoderC4FM extends P25Decoder
|
||||
|
||||
//The Costas Loop receives symbol-inversion correction requests when detected.
|
||||
//The PLL gain monitor receives sync detect/loss signals from the message framer
|
||||
mMessageFramer = new P25MessageFramer2(mCostasLoop, DecoderType.P25_PHASE1.getProtocol().getBitRate());
|
||||
mMessageFramer = new P25P1MessageFramer(mCostasLoop, DecoderType.P25_PHASE1.getProtocol().getBitRate());
|
||||
mMessageFramer.setSyncDetectListener(mPLLGainMonitor);
|
||||
mMessageFramer.setListener(getMessageProcessor());
|
||||
mMessageFramer.setSampleRate(sampleRate);
|
||||
@@ -1,19 +1,23 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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 free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
* 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.dsp.psk.DQPSKDecisionDirectedDemodulatorInstrumented;
|
||||
import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented;
|
||||
@@ -22,7 +26,7 @@ import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.Complex;
|
||||
|
||||
public class P25DecoderC4FMInstrumented extends P25DecoderC4FM
|
||||
public class P25P1DecoderC4FMInstrumented extends P25P1DecoderC4FM
|
||||
{
|
||||
private Listener<Double> mPLLPhaseErrorListener;
|
||||
private Listener<Double> mPLLFrequencyListener;
|
||||
@@ -35,7 +39,7 @@ public class P25DecoderC4FMInstrumented extends P25DecoderC4FM
|
||||
* Instrumented version of the P25 C4FM decoder that supports registering listeners to provide access to data as
|
||||
* it is being processed by the decoder.
|
||||
*/
|
||||
public P25DecoderC4FMInstrumented()
|
||||
public P25P1DecoderC4FMInstrumented()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
package io.github.dsheirer.module.decode.p25.phase1;
|
||||
|
||||
import io.github.dsheirer.controller.channel.Channel;
|
||||
import io.github.dsheirer.gui.editor.Editor;
|
||||
@@ -44,18 +44,18 @@ import javax.swing.event.ChangeListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class P25DecoderEditor extends ValidatingEditor<Channel>
|
||||
public class P25P1DecoderEditor extends ValidatingEditor<Channel>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25DecoderEditor.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P1DecoderEditor.class);
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private JComboBox<P25DecoderLSM.Modulation> mComboModulation;
|
||||
private JComboBox<P25P1DecoderLSM.Modulation> mComboModulation;
|
||||
private JCheckBox mIgnoreDataCalls;
|
||||
private JLabel mTrafficChannelPoolSizeLabel;
|
||||
private JSlider mTrafficChannelPoolSize;
|
||||
|
||||
public P25DecoderEditor()
|
||||
public P25P1DecoderEditor()
|
||||
{
|
||||
init();
|
||||
}
|
||||
@@ -64,9 +64,9 @@ public class P25DecoderEditor extends ValidatingEditor<Channel>
|
||||
{
|
||||
setLayout(new MigLayout("insets 0 0 0 0,wrap 3", "[right][grow,fill][]", ""));
|
||||
|
||||
mComboModulation = new JComboBox<P25DecoderLSM.Modulation>();
|
||||
mComboModulation.setModel(new DefaultComboBoxModel<P25DecoderLSM.Modulation>(
|
||||
P25DecoderLSM.Modulation.values()));
|
||||
mComboModulation = new JComboBox<P25P1DecoderLSM.Modulation>();
|
||||
mComboModulation.setModel(new DefaultComboBoxModel<P25P1DecoderLSM.Modulation>(
|
||||
P25P1DecoderLSM.Modulation.values()));
|
||||
mComboModulation.setEnabled(false);
|
||||
mComboModulation.addActionListener(new ActionListener()
|
||||
{
|
||||
@@ -122,7 +122,7 @@ public class P25DecoderEditor extends ValidatingEditor<Channel>
|
||||
{
|
||||
DecodeConfigP25Phase1 p25 = new DecodeConfigP25Phase1();
|
||||
|
||||
p25.setModulation((P25Decoder.Modulation)mComboModulation.getSelectedItem());
|
||||
p25.setModulation((P25P1Decoder.Modulation)mComboModulation.getSelectedItem());
|
||||
p25.setIgnoreDataCalls(mIgnoreDataCalls.isSelected());
|
||||
p25.setTrafficChannelPoolSize(mTrafficChannelPoolSize.getValue());
|
||||
|
||||
@@ -206,7 +206,7 @@ public class P25DecoderEditor extends ValidatingEditor<Channel>
|
||||
}
|
||||
else
|
||||
{
|
||||
mComboModulation.setSelectedItem(P25Decoder.Modulation.C4FM);
|
||||
mComboModulation.setSelectedItem(P25P1Decoder.Modulation.C4FM);
|
||||
mIgnoreDataCalls.setSelected(false);
|
||||
mTrafficChannelPoolSize.setValue(DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT);
|
||||
setModified(true);
|
||||
@@ -1,23 +1,25 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
package io.github.dsheirer.module.decode.p25.phase1;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window.WindowType;
|
||||
@@ -28,15 +30,23 @@ import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer;
|
||||
import io.github.dsheirer.dsp.psk.pll.AdaptivePLLGainMonitor;
|
||||
import io.github.dsheirer.dsp.psk.pll.CostasLoop;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
import io.github.dsheirer.record.binary.BinaryRecorder;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.wave.ComplexWaveSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class P25DecoderLSM extends P25Decoder
|
||||
public class P25P1DecoderLSM extends P25P1Decoder
|
||||
{
|
||||
// private final static Logger mLog = LoggerFactory.getLogger(P25DecoderLSM.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P1DecoderLSM.class);
|
||||
|
||||
protected static final float SAMPLE_COUNTER_GAIN = 0.3f;
|
||||
|
||||
@@ -44,7 +54,7 @@ public class P25DecoderLSM extends P25Decoder
|
||||
private ComplexFIRFilter2 mBasebandFilter;
|
||||
private ComplexFeedForwardGainControl mAGC = new ComplexFeedForwardGainControl(32);
|
||||
protected DQPSKGardnerDemodulator mQPSKDemodulator;
|
||||
protected P25MessageFramer2 mMessageFramer;
|
||||
protected P25P1MessageFramer mMessageFramer;
|
||||
protected CostasLoop mCostasLoop;
|
||||
protected AdaptivePLLGainMonitor mPLLGainMonitor;
|
||||
protected InterpolatingSampleBuffer mInterpolatingSampleBuffer;
|
||||
@@ -53,7 +63,7 @@ public class P25DecoderLSM extends P25Decoder
|
||||
* P25 Phase 1 - linear simulcast modulation (LSM) decoder. Uses Differential QPSK decoding with a Costas PLL and
|
||||
* a gardner timing error detector.
|
||||
*/
|
||||
public P25DecoderLSM()
|
||||
public P25P1DecoderLSM()
|
||||
{
|
||||
super(4800.0);
|
||||
setSampleRate(25000.0);
|
||||
@@ -84,7 +94,7 @@ public class P25DecoderLSM extends P25Decoder
|
||||
getDibitBroadcaster().removeListener(mMessageFramer);
|
||||
}
|
||||
|
||||
mMessageFramer = new P25MessageFramer2(mCostasLoop, DecoderType.P25_PHASE1.getProtocol().getBitRate());
|
||||
mMessageFramer = new P25P1MessageFramer(mCostasLoop, DecoderType.P25_PHASE1.getProtocol().getBitRate());
|
||||
mMessageFramer.setSyncDetectListener(mPLLGainMonitor);
|
||||
mMessageFramer.setListener(getMessageProcessor());
|
||||
mMessageFramer.setSampleRate(sampleRate);
|
||||
@@ -195,4 +205,44 @@ public class P25DecoderLSM extends P25Decoder
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
String path = "/media/denny/500G1EXT4/RadioRecordings/";
|
||||
// String input = "DFWAirport_Site_857_3875_baseband_20181213_223236.wav";
|
||||
// String output = "DFWAirport_Site_857_3875_baseband_20181213_223236";
|
||||
|
||||
String input = "P25P2_HCPM_Metrocrest_Dallas_857_7625_phase_2_not_motorola_baseband_20181213_224616_control_channel.wav";
|
||||
String output = "P25P2_HCPM_Metrocrest_Dallas_857_7625_phase_2_not_motorola_baseband_20181213_224616_control_channel";
|
||||
|
||||
|
||||
P25P1DecoderLSM decoder = new P25P1DecoderLSM();
|
||||
BinaryRecorder recorder = new BinaryRecorder(Path.of(path), output, Protocol.APCO25);
|
||||
decoder.setBufferListener(recorder.getReusableByteBufferListener());
|
||||
recorder.start();
|
||||
|
||||
File file = new File(path + input);
|
||||
|
||||
boolean running = true;
|
||||
|
||||
try(ComplexWaveSource source = new ComplexWaveSource(file))
|
||||
{
|
||||
decoder.setSampleRate(50000.0);
|
||||
source.setListener(decoder);
|
||||
source.start();
|
||||
|
||||
while(running)
|
||||
{
|
||||
source.next(200, true);
|
||||
}
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
mLog.error("Error", e);
|
||||
running = false;
|
||||
}
|
||||
|
||||
recorder.stop();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +1,23 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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 free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
* 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.dsp.psk.DQPSKGardnerDemodulatorInstrumented;
|
||||
import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented;
|
||||
@@ -22,7 +26,7 @@ import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.Complex;
|
||||
|
||||
public class P25DecoderLSMInstrumented extends P25DecoderLSM
|
||||
public class P25P1DecoderLSMInstrumented extends P25P1DecoderLSM
|
||||
{
|
||||
private Listener<Double> mPLLPhaseErrorListener;
|
||||
private Listener<Double> mPLLFrequencyListener;
|
||||
@@ -37,7 +41,7 @@ public class P25DecoderLSMInstrumented extends P25DecoderLSM
|
||||
*
|
||||
* Instrumented decoder instance.
|
||||
*/
|
||||
public P25DecoderLSMInstrumented()
|
||||
public P25P1DecoderLSMInstrumented()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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-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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
package io.github.dsheirer.module.decode.p25.phase1;
|
||||
|
||||
import io.github.dsheirer.channel.state.ChangeChannelTimeoutEvent;
|
||||
import io.github.dsheirer.channel.state.DecoderState;
|
||||
@@ -43,90 +45,94 @@ import io.github.dsheirer.module.decode.ip.IPacket;
|
||||
import io.github.dsheirer.module.decode.ip.ars.ARSPacket;
|
||||
import io.github.dsheirer.module.decode.ip.ipv4.IPV4Packet;
|
||||
import io.github.dsheirer.module.decode.ip.udp.UDPPacket;
|
||||
import io.github.dsheirer.module.decode.p25.message.P25Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.hdu.HDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.hdu.HeaderData;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCCallTermination;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCExtendedFunctionCommand;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCMessageUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCStatusUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCTelephoneInterconnectAnswerRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.ldu.EncryptionSyncParameters;
|
||||
import io.github.dsheirer.module.decode.p25.message.ldu.LDU1Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.ldu.LDU2Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.PDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCAuthenticationResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCIndividualDataServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCLocationRegistrationRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCMessageUpdateRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCStatusQueryResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCStatusUpdateRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCUnitAcknowledgeResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCUnitToUnitVoiceServiceAnswerResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCUnitToUnitVoiceServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCGroupAffiliationResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCGroupDataChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCGroupVoiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCIndividualDataChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCMessageUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCProtectionParameterBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCStatusUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCTelephoneInterconnectChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCTelephoneInterconnectChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCUnitRegistrationResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCUnitToUnitVoiceServiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCUnitToUnitVoiceServiceChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.packet.PacketMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp.SNDCPMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp.SNDCPPacketMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.umbtc.isp.UMBTCTelephoneInterconnectRequestExplicitDialing;
|
||||
import io.github.dsheirer.module.decode.p25.message.tdu.TDULinkControlMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.TSBKMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.MotorolaDenyResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.CancelServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.ExtendedFunctionResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.GroupAffiliationQueryResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.GroupDataServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.GroupVoiceServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.IndividualDataServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.LocationRegistrationRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.MessageUpdateRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.SNDCPDataChannelRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.SNDCPDataPageResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.SNDCPReconnectRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.StatusQueryResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.StatusUpdateRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.TelephoneInterconnectAnswerResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitAcknowledgeResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitRegistrationRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitToUnitVoiceServiceAnswerResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitToUnitVoiceServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.AcknowledgeResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.DenyResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.ExtendedFunctionCommand;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupAffiliationResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupDataChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupVoiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupVoiceChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupVoiceChannelGrantUpdateExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.LocationRegistrationResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.MessageUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.QueuedResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.RoamingAddressCommand;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SNDCPDataChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.StatusUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.TelephoneInterconnectAnswerRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.TelephoneInterconnectVoiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.TelephoneInterconnectVoiceChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnitRegistrationResponse;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.network.P25NetworkConfigurationMonitor;
|
||||
import io.github.dsheirer.module.decode.p25.P25DecodeEvent;
|
||||
import io.github.dsheirer.module.decode.p25.P25TrafficChannelManager;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.P25Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.hdu.HDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.hdu.HeaderData;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCCallTermination;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCExtendedFunctionCommand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCMessageUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCStatusUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCTelephoneInterconnectAnswerRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.EncryptionSyncParameters;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU1Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU2Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCAuthenticationResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCIndividualDataServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCLocationRegistrationRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCMessageUpdateRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCStatusQueryResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCStatusUpdateRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCUnitAcknowledgeResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCUnitToUnitVoiceServiceAnswerResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCUnitToUnitVoiceServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCGroupAffiliationResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCGroupDataChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCGroupVoiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCIndividualDataChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCMessageUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCProtectionParameterBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCStatusUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCTelephoneInterconnectChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCTelephoneInterconnectChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCUnitRegistrationResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCUnitToUnitVoiceServiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCUnitToUnitVoiceServiceChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.PacketMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPPacketMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.umbtc.isp.UMBTCTelephoneInterconnectRequestExplicitDialing;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDULinkControlMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.TSBKMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.MotorolaDenyResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.CancelServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.ExtendedFunctionResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.GroupAffiliationQueryResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.GroupDataServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.GroupVoiceServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.IndividualDataServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.LocationRegistrationRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.MessageUpdateRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.SNDCPDataChannelRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.SNDCPDataPageResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.SNDCPReconnectRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.StatusQueryResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.StatusUpdateRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.TelephoneInterconnectAnswerResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitAcknowledgeResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitRegistrationRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitToUnitVoiceServiceAnswerResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitToUnitVoiceServiceRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.AcknowledgeResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.DenyResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.ExtendedFunctionCommand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupAffiliationResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupDataChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupVoiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupVoiceChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupVoiceChannelGrantUpdateExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.LocationRegistrationResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.MessageUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.QueuedResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.RoamingAddressCommand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SNDCPDataChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.StatusUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.TelephoneInterconnectAnswerRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.TelephoneInterconnectVoiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.TelephoneInterconnectVoiceChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitRegistrationResponse;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.reference.Encryption;
|
||||
import io.github.dsheirer.module.decode.p25.reference.ServiceOptions;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -136,14 +142,14 @@ import org.slf4j.LoggerFactory;
|
||||
* monitoring the decoded message stream.
|
||||
*
|
||||
*/
|
||||
public class P25DecoderState extends DecoderState implements IChannelEventListener
|
||||
public class P25P1DecoderState extends DecoderState implements IChannelEventListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25DecoderState.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P1DecoderState.class);
|
||||
|
||||
private ChannelType mChannelType;
|
||||
private P25Decoder.Modulation mModulation;
|
||||
private P25P1Decoder.Modulation mModulation;
|
||||
private PatchGroupManager mPatchGroupManager = new PatchGroupManager();
|
||||
private P25NetworkConfigurationMonitor mNetworkConfigurationMonitor;
|
||||
private P25P1NetworkConfigurationMonitor mNetworkConfigurationMonitor;
|
||||
private P25TrafficChannelManager mTrafficChannelManager;
|
||||
private Listener<ChannelEvent> mChannelEventListener;
|
||||
private DecodeEvent mCurrentCallEvent;
|
||||
@@ -153,11 +159,11 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
* @param channel with configuration details
|
||||
* @param trafficChannelManager for handling traffic channel grants.
|
||||
*/
|
||||
public P25DecoderState(Channel channel, P25TrafficChannelManager trafficChannelManager)
|
||||
public P25P1DecoderState(Channel channel, P25TrafficChannelManager trafficChannelManager)
|
||||
{
|
||||
mChannelType = channel.getChannelType();
|
||||
mModulation = ((DecodeConfigP25Phase1)channel.getDecodeConfiguration()).getModulation();
|
||||
mNetworkConfigurationMonitor = new P25NetworkConfigurationMonitor(mModulation);
|
||||
mNetworkConfigurationMonitor = new P25P1NetworkConfigurationMonitor(mModulation);
|
||||
|
||||
if(trafficChannelManager != null)
|
||||
{
|
||||
@@ -176,7 +182,7 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
* Constructs an APCO-25 decoder state for a traffic channel.
|
||||
* @param channel with configuration details
|
||||
*/
|
||||
public P25DecoderState(Channel channel)
|
||||
public P25P1DecoderState(Channel channel)
|
||||
{
|
||||
this(channel, null);
|
||||
}
|
||||
@@ -184,7 +190,7 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
/**
|
||||
* Modulation type for the decoder
|
||||
*/
|
||||
public P25Decoder.Modulation getModulation()
|
||||
public P25P1Decoder.Modulation getModulation()
|
||||
{
|
||||
return mModulation;
|
||||
}
|
||||
@@ -214,6 +220,7 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
resetState();
|
||||
}
|
||||
|
||||
@@ -285,6 +292,25 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commands the traffic channel manager to process a traffic channel grant and allocate a decoder
|
||||
* to process the traffic channel.
|
||||
* @param apco25Channel to allocate
|
||||
* @param serviceOptions for the channel
|
||||
* @param identifierCollection identifying the users of the channel
|
||||
* @param opcode that identifies the type of channel grant
|
||||
* @param timestamp when the channel grant occurred.
|
||||
*/
|
||||
private void processChannelGrant(APCO25Channel apco25Channel, ServiceOptions serviceOptions,
|
||||
IdentifierCollection identifierCollection, Opcode opcode, long timestamp)
|
||||
{
|
||||
if(mTrafficChannelManager != null && apco25Channel.getValue().getFrequencyBand() != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(apco25Channel, serviceOptions, identifierCollection, opcode,
|
||||
timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternate Multi-Block Trunking Control (AMBTC)
|
||||
*
|
||||
@@ -504,6 +530,12 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
case OSP_ADJACENT_STATUS_BROADCAST:
|
||||
mNetworkConfigurationMonitor.process(ambtc);
|
||||
break;
|
||||
case OSP_NETWORK_STATUS_BROADCAST:
|
||||
mNetworkConfigurationMonitor.process(ambtc);
|
||||
break;
|
||||
case OSP_RFSS_STATUS_BROADCAST:
|
||||
mNetworkConfigurationMonitor.process(ambtc);
|
||||
break;
|
||||
|
||||
//Channel grants
|
||||
case OSP_GROUP_DATA_CHANNEL_GRANT:
|
||||
@@ -511,16 +543,12 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
{
|
||||
AMBTCGroupDataChannelGrant gdcg = (AMBTCGroupDataChannelGrant)ambtc;
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
identifierCollection.update(gdcg.getIdentifiers());
|
||||
|
||||
mTrafficChannelManager.processChannelGrant(gdcg.getChannel(), gdcg.getDataServiceOptions(),
|
||||
MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
identifierCollection.update(gdcg.getIdentifiers());
|
||||
processChannelGrant(gdcg.getChannel(), gdcg.getDataServiceOptions(),
|
||||
identifierCollection, ambtc.getHeader().getOpcode(),
|
||||
ambtc.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_GROUP_VOICE_CHANNEL_GRANT:
|
||||
@@ -532,12 +560,9 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
identifierCollection.update(gvcg.getIdentifiers());
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(gvcg.getChannel(), gvcg.getVoiceServiceOptions(),
|
||||
processChannelGrant(gvcg.getChannel(), gvcg.getVoiceServiceOptions(),
|
||||
identifierCollection, ambtc.getHeader().getOpcode(),
|
||||
ambtc.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_INDIVIDUAL_DATA_CHANNEL_GRANT:
|
||||
@@ -549,12 +574,9 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
identifierCollection.update(idcg.getIdentifiers());
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(idcg.getChannel(), idcg.getDataServiceOptions(),
|
||||
processChannelGrant(idcg.getChannel(), idcg.getDataServiceOptions(),
|
||||
identifierCollection, ambtc.getHeader().getOpcode(),
|
||||
ambtc.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
|
||||
@@ -562,16 +584,13 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
{
|
||||
AMBTCTelephoneInterconnectChannelGrant ticg = (AMBTCTelephoneInterconnectChannelGrant)ambtc;
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
identifierCollection.update(ticg.getIdentifiers());
|
||||
MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
identifierCollection.update(ticg.getIdentifiers());
|
||||
|
||||
mTrafficChannelManager.processChannelGrant(ticg.getChannel(), ticg.getVoiceServiceOptions(),
|
||||
processChannelGrant(ticg.getChannel(), ticg.getVoiceServiceOptions(),
|
||||
identifierCollection, ambtc.getHeader().getOpcode(),
|
||||
ambtc.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
@@ -579,16 +598,13 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
{
|
||||
AMBTCTelephoneInterconnectChannelGrantUpdate ticgu = (AMBTCTelephoneInterconnectChannelGrantUpdate)ambtc;
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
identifierCollection.update(ticgu.getIdentifiers());
|
||||
MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
identifierCollection.update(ticgu.getIdentifiers());
|
||||
|
||||
mTrafficChannelManager.processChannelGrant(ticgu.getChannel(), ticgu.getVoiceServiceOptions(),
|
||||
processChannelGrant(ticgu.getChannel(), ticgu.getVoiceServiceOptions(),
|
||||
identifierCollection, ambtc.getHeader().getOpcode(),
|
||||
ambtc.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
|
||||
@@ -596,16 +612,13 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
{
|
||||
AMBTCUnitToUnitVoiceServiceChannelGrant uuvscg = (AMBTCUnitToUnitVoiceServiceChannelGrant)ambtc;
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
identifierCollection.update(uuvscg.getIdentifiers());
|
||||
MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
identifierCollection.update(uuvscg.getIdentifiers());
|
||||
|
||||
mTrafficChannelManager.processChannelGrant(uuvscg.getChannel(), uuvscg.getVoiceServiceOptions(),
|
||||
processChannelGrant(uuvscg.getChannel(), uuvscg.getVoiceServiceOptions(),
|
||||
identifierCollection, ambtc.getHeader().getOpcode(),
|
||||
ambtc.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
@@ -613,16 +626,13 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
{
|
||||
AMBTCUnitToUnitVoiceServiceChannelGrantUpdate uuvscgu = (AMBTCUnitToUnitVoiceServiceChannelGrantUpdate)ambtc;
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
identifierCollection.update(uuvscgu.getIdentifiers());
|
||||
MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
identifierCollection.remove(IdentifierClass.USER);
|
||||
identifierCollection.update(uuvscgu.getIdentifiers());
|
||||
|
||||
mTrafficChannelManager.processChannelGrant(uuvscgu.getChannel(), uuvscgu.getVoiceServiceOptions(),
|
||||
processChannelGrant(uuvscgu.getChannel(), uuvscgu.getVoiceServiceOptions(),
|
||||
identifierCollection, ambtc.getHeader().getOpcode(),
|
||||
ambtc.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_UNIT_TO_UNIT_ANSWER_REQUEST:
|
||||
@@ -1171,11 +1181,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiers.update(mPatchGroupManager.update(identifier));
|
||||
}
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(gdcg.getChannel(), gdcg.getDataServiceOptions(),
|
||||
processChannelGrant(gdcg.getChannel(), gdcg.getDataServiceOptions(),
|
||||
identifiers, tsbk.getOpcode(), gdcg.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_GROUP_VOICE_CHANNEL_GRANT:
|
||||
@@ -1191,11 +1198,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiers.update(mPatchGroupManager.update(identifier));
|
||||
}
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(gvcg.getChannel(), gvcg.getVoiceServiceOptions(),
|
||||
processChannelGrant(gvcg.getChannel(), gvcg.getVoiceServiceOptions(),
|
||||
identifiers, tsbk.getOpcode(), gvcg.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_GROUP_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
@@ -1208,11 +1212,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiersA.remove(IdentifierClass.USER);
|
||||
identifiersA.update(mPatchGroupManager.update(gvcgu.getGroupAddressA()));
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(gvcgu.getChannelA(), null, identifiersA,
|
||||
processChannelGrant(gvcgu.getChannelA(), null, identifiersA,
|
||||
tsbk.getOpcode(), gvcgu.getTimestamp());
|
||||
}
|
||||
|
||||
if(gvcgu.hasGroupB())
|
||||
{
|
||||
@@ -1221,11 +1222,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiersB.remove(IdentifierClass.USER);
|
||||
identifiersB.update(mPatchGroupManager.update(gvcgu.getGroupAddressB()));
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(gvcgu.getChannelB(), null, identifiersB,
|
||||
processChannelGrant(gvcgu.getChannelB(), null, identifiersB,
|
||||
tsbk.getOpcode(), gvcgu.getTimestamp());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1239,11 +1237,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiers.remove(IdentifierClass.USER);
|
||||
identifiers.update(mPatchGroupManager.update(gvcgue.getGroupAddress()));
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(gvcgue.getChannel(), gvcgue.getVoiceServiceOptions(),
|
||||
processChannelGrant(gvcgue.getChannel(), gvcgue.getVoiceServiceOptions(),
|
||||
identifiers, tsbk.getOpcode(), gvcgue.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
|
||||
@@ -1256,11 +1251,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiers.remove(IdentifierClass.USER);
|
||||
identifiers.update(uuvcg.getIdentifiers());
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(uuvcg.getChannel(), null, identifiers,
|
||||
processChannelGrant(uuvcg.getChannel(), null, identifiers,
|
||||
tsbk.getOpcode(), uuvcg.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
@@ -1273,11 +1265,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiers.remove(IdentifierClass.USER);
|
||||
identifiers.update(uuvcgu.getIdentifiers());
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(uuvcgu.getChannel(), null, identifiers,
|
||||
processChannelGrant(uuvcgu.getChannel(), null, identifiers,
|
||||
tsbk.getOpcode(), uuvcgu.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
|
||||
@@ -1290,11 +1279,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiers.remove(IdentifierClass.USER);
|
||||
identifiers.update(tivcg.getIdentifiers());
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(tivcg.getChannel(), tivcg.getVoiceServiceOptions(),
|
||||
processChannelGrant(tivcg.getChannel(), tivcg.getVoiceServiceOptions(),
|
||||
identifiers, tsbk.getOpcode(), tivcg.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
@@ -1307,11 +1293,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiers.remove(IdentifierClass.USER);
|
||||
identifiers.update(tivcgu.getIdentifiers());
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(tivcgu.getChannel(), tivcgu.getVoiceServiceOptions(),
|
||||
processChannelGrant(tivcgu.getChannel(), tivcgu.getVoiceServiceOptions(),
|
||||
identifiers, tsbk.getOpcode(), tivcgu.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_SNDCP_DATA_CHANNEL_GRANT:
|
||||
@@ -1324,11 +1307,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiers.remove(IdentifierClass.USER);
|
||||
identifiers.update(dcg.getIdentifiers());
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(dcg.getChannel(), dcg.getServiceOptions(),
|
||||
processChannelGrant(dcg.getChannel(), dcg.getServiceOptions(),
|
||||
identifiers, tsbk.getOpcode(), dcg.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOTOROLA_OSP_PATCH_GROUP_CHANNEL_GRANT:
|
||||
@@ -1344,11 +1324,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiers.update(mPatchGroupManager.update(identifier));
|
||||
}
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(pgvcg.getChannel(), pgvcg.getVoiceServiceOptions(),
|
||||
processChannelGrant(pgvcg.getChannel(), pgvcg.getVoiceServiceOptions(),
|
||||
identifiers, tsbk.getOpcode(), pgvcg.getTimestamp());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOTOROLA_OSP_PATCH_GROUP_CHANNEL_GRANT_UPDATE:
|
||||
@@ -1361,11 +1338,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiersPG1.remove(IdentifierClass.USER);
|
||||
identifiersPG1.update(mPatchGroupManager.update(pgvcgu.getPatchGroup1()));
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(pgvcgu.getChannel1(), null, identifiersPG1,
|
||||
processChannelGrant(pgvcgu.getChannel1(), null, identifiersPG1,
|
||||
tsbk.getOpcode(), pgvcgu.getTimestamp());
|
||||
}
|
||||
|
||||
if(pgvcgu.hasPatchGroup2())
|
||||
{
|
||||
@@ -1374,11 +1348,8 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen
|
||||
identifiersPG2.remove(IdentifierClass.USER);
|
||||
identifiersPG2.update(mPatchGroupManager.update(pgvcgu.getPatchGroup2()));
|
||||
|
||||
if(mTrafficChannelManager != null)
|
||||
{
|
||||
mTrafficChannelManager.processChannelGrant(pgvcgu.getChannel2(), null,
|
||||
processChannelGrant(pgvcgu.getChannel2(), null,
|
||||
identifiersPG2, tsbk.getOpcode(), pgvcgu.getTimestamp());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1,4 +1,24 @@
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
@@ -10,10 +30,10 @@ import java.util.BitSet;
|
||||
/**
|
||||
* Utility class to process interleave of P25 Voice and Data messages.
|
||||
*/
|
||||
public class P25Interleave
|
||||
public class P25P1Interleave
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger(P25Interleave.class);
|
||||
LoggerFactory.getLogger(P25P1Interleave.class);
|
||||
|
||||
public static int[] DATA_INTERLEAVE = new int[]{0, 1, 2, 3, 52, 53, 54, 55, 100,
|
||||
101, 102, 103, 148, 149, 150, 151, 4, 5, 6, 7, 56, 57, 58, 59, 104, 105, 106, 107, 152, 153,
|
||||
@@ -1,43 +1,43 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
package io.github.dsheirer.module.decode.p25.phase1;
|
||||
|
||||
import io.github.dsheirer.bits.BitSetFullException;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop;
|
||||
import io.github.dsheirer.dsp.symbol.Dibit;
|
||||
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.message.Message;
|
||||
import io.github.dsheirer.message.SyncLossMessage;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.p25.message.P25Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.P25MessageFactory;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.PDUMessageFactory;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.umbtc.UMBTCMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.TSBKMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.TSBKMessageFactory;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrant;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
import io.github.dsheirer.module.decode.p25.audio.P25P1CallSequenceRecorder;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.P25Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.P25MessageFactory;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUMessageFactory;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.TSBKMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.TSBKMessageFactory;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
import io.github.dsheirer.record.binary.BinaryReader;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
@@ -52,17 +52,17 @@ import java.nio.file.Paths;
|
||||
* P25 Sync Detector and Message Framer. Includes capability to detect PLL out-of-phase lock errors
|
||||
* and issue phase corrections.
|
||||
*/
|
||||
public class P25MessageFramer2 implements Listener<Dibit>, IDataUnitDetectListener
|
||||
public class P25P1MessageFramer implements Listener<Dibit>, IP25P1DataUnitDetectListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25MessageFramer2.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P1MessageFramer.class);
|
||||
|
||||
private P25DataUnitDetector mDataUnitDetector;
|
||||
private P25ChannelStatusProcessor mChannelStatusProcessor = new P25ChannelStatusProcessor();
|
||||
private P25P1DataUnitDetector mDataUnitDetector;
|
||||
private P25P1ChannelStatusProcessor mChannelStatusProcessor = new P25P1ChannelStatusProcessor();
|
||||
private Listener<Message> mMessageListener;
|
||||
|
||||
private boolean mAssemblingMessage = false;
|
||||
private CorrectedBinaryMessage mBinaryMessage;
|
||||
private DataUnitID mDataUnitID;
|
||||
private P25P1DataUnitID mDataUnitID;
|
||||
private PDUSequence mPDUSequence;
|
||||
private int[] mCorrectedNID;
|
||||
private int mNAC;
|
||||
@@ -72,13 +72,13 @@ public class P25MessageFramer2 implements Listener<Dibit>, IDataUnitDetectListen
|
||||
private long mCurrentTime = System.currentTimeMillis();
|
||||
private ISyncDetectListener mSyncDetectListener;
|
||||
|
||||
public P25MessageFramer2(IPhaseLockedLoop phaseLockedLoop, int bitRate)
|
||||
public P25P1MessageFramer(IPhaseLockedLoop phaseLockedLoop, int bitRate)
|
||||
{
|
||||
mDataUnitDetector = new P25DataUnitDetector(this, phaseLockedLoop);
|
||||
mDataUnitDetector = new P25P1DataUnitDetector(this, phaseLockedLoop);
|
||||
mBitRate = bitRate;
|
||||
}
|
||||
|
||||
public P25MessageFramer2(int bitRate)
|
||||
public P25P1MessageFramer(int bitRate)
|
||||
{
|
||||
this(null, bitRate);
|
||||
}
|
||||
@@ -144,7 +144,7 @@ public class P25MessageFramer2 implements Listener<Dibit>, IDataUnitDetectListen
|
||||
mMessageListener = messageListener;
|
||||
}
|
||||
|
||||
public P25DataUnitDetector getDataUnitDetector()
|
||||
public P25P1DataUnitDetector getDataUnitDetector()
|
||||
{
|
||||
return mDataUnitDetector;
|
||||
}
|
||||
@@ -227,8 +227,8 @@ public class P25MessageFramer2 implements Listener<Dibit>, IDataUnitDetectListen
|
||||
mPDUSequence.getHeader().getBlocksToFollowCount() > 0)
|
||||
{
|
||||
//Setup to catch the sequence of data blocks that follow the header
|
||||
mDataUnitID = DataUnitID.PACKET_DATA_UNIT;
|
||||
mBinaryMessage = new CorrectedBinaryMessage(DataUnitID.PACKET_DATA_UNIT.getMessageLength());
|
||||
mDataUnitID = P25P1DataUnitID.PACKET_DATA_UNIT;
|
||||
mBinaryMessage = new CorrectedBinaryMessage(P25P1DataUnitID.PACKET_DATA_UNIT.getMessageLength());
|
||||
mAssemblingMessage = true;
|
||||
}
|
||||
else
|
||||
@@ -291,8 +291,8 @@ public class P25MessageFramer2 implements Listener<Dibit>, IDataUnitDetectListen
|
||||
else
|
||||
{
|
||||
//Setup to catch the next data block
|
||||
mDataUnitID = DataUnitID.PACKET_DATA_UNIT;
|
||||
mBinaryMessage = new CorrectedBinaryMessage(DataUnitID.PACKET_DATA_UNIT.getMessageLength());
|
||||
mDataUnitID = P25P1DataUnitID.PACKET_DATA_UNIT;
|
||||
mBinaryMessage = new CorrectedBinaryMessage(P25P1DataUnitID.PACKET_DATA_UNIT.getMessageLength());
|
||||
mAssemblingMessage = true;
|
||||
}
|
||||
}
|
||||
@@ -319,13 +319,13 @@ public class P25MessageFramer2 implements Listener<Dibit>, IDataUnitDetectListen
|
||||
{
|
||||
updateBitsProcessed(mDataUnitID.getMessageLength());
|
||||
mBinaryMessage = new CorrectedBinaryMessage(mDataUnitID.getMessageLength());
|
||||
if(mDataUnitID == DataUnitID.TRUNKING_SIGNALING_BLOCK_1)
|
||||
if(mDataUnitID == P25P1DataUnitID.TRUNKING_SIGNALING_BLOCK_1)
|
||||
{
|
||||
mDataUnitID = DataUnitID.TRUNKING_SIGNALING_BLOCK_2;
|
||||
mDataUnitID = P25P1DataUnitID.TRUNKING_SIGNALING_BLOCK_2;
|
||||
}
|
||||
else if(mDataUnitID == DataUnitID.TRUNKING_SIGNALING_BLOCK_2)
|
||||
else if(mDataUnitID == P25P1DataUnitID.TRUNKING_SIGNALING_BLOCK_2)
|
||||
{
|
||||
mDataUnitID = DataUnitID.TRUNKING_SIGNALING_BLOCK_3;
|
||||
mDataUnitID = P25P1DataUnitID.TRUNKING_SIGNALING_BLOCK_3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -376,7 +376,7 @@ public class P25MessageFramer2 implements Listener<Dibit>, IDataUnitDetectListen
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataUnitDetected(DataUnitID dataUnitID, int nac, int bitErrors, int discardedDibits, int[] correctedNid)
|
||||
public void dataUnitDetected(P25P1DataUnitID dataUnitID, int nac, int bitErrors, int discardedDibits, int[] correctedNid)
|
||||
{
|
||||
if(discardedDibits > 0)
|
||||
{
|
||||
@@ -428,75 +428,39 @@ public class P25MessageFramer2 implements Listener<Dibit>, IDataUnitDetectListen
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
boolean pduOnly = false;
|
||||
boolean mbtcOnly = false;
|
||||
boolean sndcpOnly = false;
|
||||
boolean ippacketOnly = false;
|
||||
boolean patchOnly = false;
|
||||
P25P1DecoderLSM decoderLSM = new P25P1DecoderLSM();
|
||||
|
||||
P25MessageFramer2 messageFramer = new P25MessageFramer2(null, DecoderType.P25_PHASE1.getProtocol().getBitRate());
|
||||
messageFramer.setListener(new Listener<Message>()
|
||||
|
||||
// Path path = Paths.get("/media/denny/500G1EXT4/RadioRecordings/APCO25P2/DFW Airport Encrypted/20190719_073751_9600BPS_APCO25PHASE1_DFWAirport_Site_857_3875_baseband_20181213_223236.bits");
|
||||
Path path = Paths.get("/media/denny/500G1EXT4/RadioRecordings/20190720_071117_9600BPS_APCO25PHASE1_P25P2_HCPM_Metrocrest_Dallas_857_7625_phase_2_not_motorola_baseband_20181213_224616_control_channel.bits");
|
||||
|
||||
P25P1MessageFramer messageFramer = new P25P1MessageFramer(null, DecoderType.P25_PHASE1.getProtocol().getBitRate());
|
||||
|
||||
try(BinaryReader reader = new BinaryReader(path, 200))
|
||||
{
|
||||
while(reader.hasNext())
|
||||
{
|
||||
messageFramer.receive(reader.next());
|
||||
}
|
||||
}
|
||||
catch(Exception ioe)
|
||||
{
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
||||
P25P1MessageProcessor messageProcessor = new P25P1MessageProcessor();
|
||||
P25P1CallSequenceRecorder frameRecorder = new P25P1CallSequenceRecorder(new UserPreferences(), 154250000, "", "");
|
||||
messageFramer.setListener(messageProcessor);
|
||||
messageProcessor.setMessageListener(new Listener<IMessage>()
|
||||
{
|
||||
@Override
|
||||
public void receive(Message message)
|
||||
public void receive(IMessage message)
|
||||
{
|
||||
if(mbtcOnly)
|
||||
{
|
||||
if(message instanceof AMBTCMessage || message instanceof UMBTCMessage)
|
||||
{
|
||||
mLog.debug(message.toString());
|
||||
}
|
||||
}
|
||||
else if(pduOnly)
|
||||
{
|
||||
String s = message.toString();
|
||||
|
||||
if(s.contains(" PDU "))
|
||||
{
|
||||
mLog.debug(s);
|
||||
}
|
||||
}
|
||||
else if(sndcpOnly)
|
||||
{
|
||||
String s = message.toString();
|
||||
|
||||
if(s.contains("SNDCP"))
|
||||
{
|
||||
mLog.debug(s);
|
||||
}
|
||||
}
|
||||
else if(ippacketOnly)
|
||||
{
|
||||
String s = message.toString();
|
||||
|
||||
if(s.contains("IPPKT") || s.contains("SNDCP") || s.contains(" PDU "))
|
||||
{
|
||||
mLog.debug(s);
|
||||
}
|
||||
}
|
||||
else if(patchOnly)
|
||||
{
|
||||
if(message instanceof PatchGroupVoiceChannelGrant || message instanceof PatchGroupVoiceChannelGrantUpdate)
|
||||
{
|
||||
mLog.debug(message.toString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
String a = message.toString();
|
||||
mLog.debug(a);
|
||||
}
|
||||
frameRecorder.receive(message);
|
||||
mLog.debug(message.toString());
|
||||
}
|
||||
});
|
||||
|
||||
// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181102_102339_9600BPS_CNYICC_Onondaga Simulcast_LCN 08.bits");
|
||||
// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181103_134948_9600BPS_CNYICC_Oswego Simulcast_LCN 04.bits");
|
||||
// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181103_144312_9600BPS_CNYICC_Oswego Simulcast_LCN 04.bits"); //Interesting UDP port 231 packets (oswego LCN 4)
|
||||
// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181103_144429_9600BPS_CNYICC_Onondaga Simulcast_LCN 09.bits");
|
||||
// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181103_144437_9600BPS_CNYICC_Onondaga Simulcast_LCN 10.bits");
|
||||
Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181202_064827_9600BPS_CNYICC_Onondaga Simulcast_LCN 15 Control.bits");
|
||||
|
||||
|
||||
|
||||
try(BinaryReader reader = new BinaryReader(path, 200))
|
||||
{
|
||||
@@ -510,7 +474,6 @@ public class P25MessageFramer2 implements Listener<Dibit>, IDataUnitDetectListen
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
mLog.debug("NIDS Detected: " + messageFramer.getDataUnitDetector().getNIDDetectionCount());
|
||||
frameRecorder.stop();
|
||||
}
|
||||
}
|
||||
@@ -1,45 +1,51 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
*/
|
||||
package io.github.dsheirer.module.decode.p25.phase1;
|
||||
|
||||
import io.github.dsheirer.channel.IChannelDescriptor;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.message.Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.IFrequencyBand;
|
||||
import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class P25MessageProcessor implements Listener<Message>
|
||||
public class P25P1MessageProcessor implements Listener<Message>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25MessageProcessor.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P1MessageProcessor.class);
|
||||
|
||||
private Listener<IMessage> mMessageListener;
|
||||
|
||||
/* Map of up to 16 band identifiers per RFSS. These identifier update
|
||||
* messages are inserted into any message that conveys channel information
|
||||
* so that the uplink/downlink frequencies can be calculated */
|
||||
private Map<Integer,IFrequencyBand> mFrequencyBandMap = new HashMap<Integer,IFrequencyBand>();
|
||||
private Map<Integer,IFrequencyBand> mFrequencyBandMap = new TreeMap<Integer,IFrequencyBand>();
|
||||
|
||||
public P25MessageProcessor()
|
||||
public P25P1MessageProcessor()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,47 +1,51 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.network;
|
||||
package io.github.dsheirer.module.decode.p25.phase1;
|
||||
|
||||
import io.github.dsheirer.channel.IChannelDescriptor;
|
||||
import io.github.dsheirer.module.decode.p25.P25Decoder;
|
||||
import io.github.dsheirer.module.decode.p25.message.IFrequencyBand;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCAdjacentSiteStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCAdjacentSiteStatusBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCNetworkStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCNetworkStatusBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCRFSSStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCRFSSStatusBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCSecondaryControlChannelBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCSecondaryControlChannelBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCSystemServiceBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCAdjacentStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.TSBKMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.AdjacentStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.NetworkStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.RFSSStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SNDCPDataChannelAnnouncementExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SecondaryControlChannelBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SystemServiceBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCAdjacentSiteStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCAdjacentSiteStatusBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCNetworkStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCNetworkStatusBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCRFSSStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCRFSSStatusBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCSecondaryControlChannelBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCSecondaryControlChannelBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCSystemServiceBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCAdjacentStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCNetworkStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCRFSSStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.TSBKMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.AdjacentStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.NetworkStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.RFSSStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SNDCPDataChannelAnnouncementExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SecondaryControlChannelBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SecondaryControlChannelBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SystemServiceBroadcast;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -55,21 +59,23 @@ import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Tracks the network configuration details of a P25 network from the broadcast messages
|
||||
* Tracks the network configuration details of a P25 Phase 1 network from the broadcast messages
|
||||
*/
|
||||
public class P25NetworkConfigurationMonitor
|
||||
public class P25P1NetworkConfigurationMonitor
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25NetworkConfigurationMonitor.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P1NetworkConfigurationMonitor.class);
|
||||
|
||||
private Map<Integer,IFrequencyBand> mFrequencyBandMap = new HashMap<>();
|
||||
|
||||
//Network Status Messages
|
||||
private AMBTCNetworkStatusBroadcast mAMBTCNetworkStatusBroadcast;
|
||||
private NetworkStatusBroadcast mTSBKNetworkStatusBroadcast;
|
||||
private LCNetworkStatusBroadcast mLCNetworkStatusBroadcast;
|
||||
private LCNetworkStatusBroadcastExplicit mLCNetworkStatusBroadcastExplicit;
|
||||
|
||||
//Current Site Status Messagese
|
||||
private RFSSStatusBroadcast mTSBKRFSSStatusBroadcast;
|
||||
private AMBTCRFSSStatusBroadcast mAMBTCRFSSStatusBroadcast;
|
||||
private LCRFSSStatusBroadcast mLCRFSSStatusBroadcast;
|
||||
private LCRFSSStatusBroadcastExplicit mLCRFSSStatusBroadcastExplicit;
|
||||
|
||||
@@ -89,14 +95,14 @@ public class P25NetworkConfigurationMonitor
|
||||
private Map<Integer,LCAdjacentSiteStatusBroadcastExplicit> mLCNeighborSitesExplicit = new HashMap<>();
|
||||
private Map<Integer,AdjacentStatusBroadcast> mTSBKNeighborSites = new HashMap<>();
|
||||
|
||||
private P25Decoder.Modulation mModulation;
|
||||
private P25P1Decoder.Modulation mModulation;
|
||||
|
||||
/**
|
||||
* Constructs a network configuration monitor.
|
||||
*
|
||||
* @param modulation type used by the decoder
|
||||
*/
|
||||
public P25NetworkConfigurationMonitor(P25Decoder.Modulation modulation)
|
||||
public P25P1NetworkConfigurationMonitor(P25P1Decoder.Modulation modulation)
|
||||
{
|
||||
mModulation = modulation;
|
||||
}
|
||||
@@ -146,6 +152,14 @@ public class P25NetworkConfigurationMonitor
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OSP_SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT:
|
||||
if(tsbk instanceof SecondaryControlChannelBroadcastExplicit)
|
||||
{
|
||||
SecondaryControlChannelBroadcastExplicit sccbe = (SecondaryControlChannelBroadcastExplicit)tsbk;
|
||||
IChannelDescriptor channel = sccbe.getChannel();
|
||||
mSecondaryControlChannels.put(channel.toString(), channel);
|
||||
}
|
||||
break;
|
||||
case OSP_ADJACENT_STATUS_BROADCAST:
|
||||
if(tsbk instanceof AdjacentStatusBroadcast)
|
||||
{
|
||||
@@ -176,6 +190,18 @@ public class P25NetworkConfigurationMonitor
|
||||
mAMBTCNeighborSites.put((int)aasb.getSite().getValue(), aasb);
|
||||
}
|
||||
break;
|
||||
case OSP_NETWORK_STATUS_BROADCAST:
|
||||
if(ambtc instanceof AMBTCNetworkStatusBroadcast)
|
||||
{
|
||||
mAMBTCNetworkStatusBroadcast = (AMBTCNetworkStatusBroadcast)ambtc;
|
||||
}
|
||||
break;
|
||||
case OSP_RFSS_STATUS_BROADCAST:
|
||||
if(ambtc instanceof AMBTCRFSSStatusBroadcast)
|
||||
{
|
||||
mAMBTCRFSSStatusBroadcast = (AMBTCRFSSStatusBroadcast)ambtc;
|
||||
}
|
||||
break;
|
||||
//TODO: process the rest of the messages here
|
||||
}
|
||||
}
|
||||
@@ -270,14 +296,29 @@ public class P25NetworkConfigurationMonitor
|
||||
|
||||
public void reset()
|
||||
{
|
||||
|
||||
mFrequencyBandMap.clear();
|
||||
mAMBTCNetworkStatusBroadcast = null;
|
||||
mTSBKNetworkStatusBroadcast = null;
|
||||
mLCNetworkStatusBroadcast = null;
|
||||
mLCNetworkStatusBroadcastExplicit = null;
|
||||
mTSBKRFSSStatusBroadcast = null;
|
||||
mLCRFSSStatusBroadcast = null;
|
||||
mLCRFSSStatusBroadcastExplicit = null;
|
||||
mSecondaryControlChannels.clear();
|
||||
mSNDCPDataChannel = null;
|
||||
mTSBKSystemServiceBroadcast = null;
|
||||
mLCSystemServiceBroadcast = null;
|
||||
mAMBTCNeighborSites = new HashMap<>();
|
||||
mLCNeighborSites.clear();
|
||||
mLCNeighborSitesExplicit.clear();
|
||||
mTSBKNeighborSites.clear();
|
||||
}
|
||||
|
||||
public String getActivitySummary()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("Activity Summary - Decoder:P25 ").append(mModulation.getLabel());
|
||||
sb.append("Activity Summary - Decoder:P25 Phase 1 ").append(mModulation.getLabel());
|
||||
|
||||
sb.append("\n\nNetwork\n");
|
||||
if(mTSBKNetworkStatusBroadcast != null)
|
||||
@@ -287,6 +328,12 @@ public class P25NetworkConfigurationMonitor
|
||||
sb.append(" SYSTEM:").append(mTSBKNetworkStatusBroadcast.getSystem());
|
||||
sb.append(" LRA:").append(mTSBKNetworkStatusBroadcast.getLocationRegistrationArea());
|
||||
}
|
||||
else if(mAMBTCNetworkStatusBroadcast != null)
|
||||
{
|
||||
sb.append(" NAC:").append(mAMBTCNetworkStatusBroadcast.getNAC());
|
||||
sb.append(" WACN:").append(mAMBTCNetworkStatusBroadcast.getWacn());
|
||||
sb.append(" SYSTEM:").append(mAMBTCNetworkStatusBroadcast.getSystem());
|
||||
}
|
||||
else if(mLCNetworkStatusBroadcast != null)
|
||||
{
|
||||
sb.append(" WACN:").append(mLCNetworkStatusBroadcast.getWACN());
|
||||
@@ -334,6 +381,18 @@ public class P25NetworkConfigurationMonitor
|
||||
sb.append(" DOWNLINK:").append(mLCRFSSStatusBroadcastExplicit.getChannel().getDownlinkFrequency());
|
||||
sb.append(" UPLINK:").append(mLCRFSSStatusBroadcastExplicit.getChannel().getUplinkFrequency()).append("\n");
|
||||
}
|
||||
else if(mAMBTCRFSSStatusBroadcast != null)
|
||||
{
|
||||
sb.append(" SYSTEM:").append(mAMBTCRFSSStatusBroadcast.getSystem());
|
||||
sb.append(" SITE:").append(mAMBTCRFSSStatusBroadcast.getSite());
|
||||
sb.append(" RF SUBSYSTEM:").append(mAMBTCRFSSStatusBroadcast.getRFSS());
|
||||
sb.append(" LOCATION REGISTRATION AREA:").append(mAMBTCRFSSStatusBroadcast.getLRA());
|
||||
sb.append(" STATUS:").append(mAMBTCRFSSStatusBroadcast.isActiveNetworkConnectionToRfssControllerSite() ?
|
||||
"ACTIVE RFSS NETWORK CONNECTION\n" : "\n");
|
||||
sb.append(" PRI CONTROL CHANNEL:").append(mAMBTCRFSSStatusBroadcast.getChannel());
|
||||
sb.append(" DOWNLINK:").append(mAMBTCRFSSStatusBroadcast.getChannel().getDownlinkFrequency());
|
||||
sb.append(" UPLINK:").append(mAMBTCRFSSStatusBroadcast.getChannel().getUplinkFrequency()).append("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(" UNKNOWN");
|
||||
@@ -1,19 +1,23 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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 free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.p25;
|
||||
* 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.bits.MultiSyncPatternMatcher;
|
||||
import io.github.dsheirer.bits.SoftSyncDetector;
|
||||
@@ -22,10 +26,9 @@ import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop;
|
||||
import io.github.dsheirer.dsp.symbol.Dibit;
|
||||
import io.github.dsheirer.dsp.symbol.FrameSync;
|
||||
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
|
||||
public class P25SyncDetector implements Listener<Dibit>
|
||||
public class P25P1SyncDetector implements Listener<Dibit>
|
||||
{
|
||||
/* Determines the threshold for sync pattern soft matching */
|
||||
private static final int SYNC_MATCH_THRESHOLD = 4;
|
||||
@@ -45,13 +48,13 @@ public class P25SyncDetector implements Listener<Dibit>
|
||||
private PLLPhaseInversionDetector mInversionDetector90CCW;
|
||||
private PLLPhaseInversionDetector mInversionDetector180;
|
||||
|
||||
public P25SyncDetector(ISyncDetectListener syncDetectListener, IPhaseLockedLoop phaseLockedLoop)
|
||||
public P25P1SyncDetector(ISyncDetectListener syncDetectListener, IPhaseLockedLoop phaseLockedLoop)
|
||||
{
|
||||
//TODO: since we're only going to feed dibits to find next frame, it makes sense to
|
||||
//TODO: update the sync lost parameter to 48 bits ....
|
||||
|
||||
//TODO: only enable the phase inversion detectors when we're in a sync-lost state
|
||||
mMatcher = new MultiSyncPatternMatcher(syncDetectListener, DataUnitID.LOGICAL_LINK_DATA_UNIT_1.getMessageLength(), 48);
|
||||
mMatcher = new MultiSyncPatternMatcher(syncDetectListener, P25P1DataUnitID.LOGICAL_LINK_DATA_UNIT_1.getMessageLength(), 48);
|
||||
mPrimarySyncDetector = new SoftSyncDetector(FrameSync.P25_PHASE1_NORMAL.getSync(), SYNC_MATCH_THRESHOLD, syncDetectListener);
|
||||
mMatcher.add(mPrimarySyncDetector);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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.message;
|
||||
|
||||
import io.github.dsheirer.channel.IChannelDescriptor;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
|
||||
/**
|
||||
* Interface for adjacent site (ie neighbor) messages
|
||||
*/
|
||||
public interface IAdjacentSite
|
||||
{
|
||||
String getUniqueID();
|
||||
|
||||
Identifier getRFSSId();
|
||||
|
||||
Identifier getSystemID();
|
||||
|
||||
Identifier getSiteID();
|
||||
|
||||
Identifier getLRAId();
|
||||
|
||||
String getSystemServiceClass();
|
||||
|
||||
IChannelDescriptor getChannel();
|
||||
}
|
||||
@@ -1,19 +1,23 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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 free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.p25.message;
|
||||
* 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.message;
|
||||
|
||||
public interface IFrequencyBand
|
||||
{
|
||||
@@ -1,19 +1,23 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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 free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.p25.message;
|
||||
* 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.message;
|
||||
|
||||
|
||||
import io.github.dsheirer.channel.IChannelDescriptor;
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,13 +17,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.module.decode.p25.message;
|
||||
package io.github.dsheirer.module.decode.p25.phase1.message;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.message.Message;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.APCO25Nac;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
|
||||
public abstract class P25Message extends Message
|
||||
@@ -102,7 +102,7 @@ public abstract class P25Message extends Message
|
||||
/**
|
||||
* Data Unit ID indicates the type of P25 message
|
||||
*/
|
||||
public abstract DataUnitID getDUID();
|
||||
public abstract P25P1DataUnitID getDUID();
|
||||
|
||||
public String toString()
|
||||
{
|
||||
@@ -1,29 +1,33 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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 free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.p25.message;
|
||||
* 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.message;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.hdu.HDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.ldu.LDU1Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.ldu.LDU2Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.tdu.TDULinkControlMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.tdu.TDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.vselp.VSELP1Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.vselp.VSELP2Message;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.hdu.HDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU1Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU2Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDULinkControlMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.vselp.VSELP1Message;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.vselp.VSELP2Message;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -46,7 +50,7 @@ public class P25MessageFactory
|
||||
* correction
|
||||
* @return constructed message parser
|
||||
*/
|
||||
public static P25Message create(DataUnitID dataUnitID, int nac, long timestamp, CorrectedBinaryMessage message)
|
||||
public static P25Message create(P25P1DataUnitID dataUnitID, int nac, long timestamp, CorrectedBinaryMessage message)
|
||||
{
|
||||
switch(dataUnitID)
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,11 +18,11 @@
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.p25.message;
|
||||
package io.github.dsheirer.module.decode.p25.phase1.message;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -32,16 +32,16 @@ import java.util.List;
|
||||
*/
|
||||
public class UnknownP25Message extends P25Message
|
||||
{
|
||||
private DataUnitID mDataUnitID;
|
||||
private P25P1DataUnitID mDataUnitID;
|
||||
|
||||
public UnknownP25Message(CorrectedBinaryMessage message, int nac, long timestamp, DataUnitID dataUnitID)
|
||||
public UnknownP25Message(CorrectedBinaryMessage message, int nac, long timestamp, P25P1DataUnitID dataUnitID)
|
||||
{
|
||||
super(message, nac);
|
||||
mDataUnitID = dataUnitID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataUnitID getDUID()
|
||||
public P25P1DataUnitID getDUID()
|
||||
{
|
||||
return mDataUnitID;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,12 +18,12 @@
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.p25.message.filter;
|
||||
package io.github.dsheirer.module.decode.p25.phase1.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.hdu.HDUMessage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class HDUMessageFilter extends Filter<IMessage>
|
||||
{
|
||||
public HDUMessageFilter()
|
||||
{
|
||||
super("Header Data Unit");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passes(IMessage message)
|
||||
{
|
||||
return mEnabled && canProcess(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(IMessage message)
|
||||
{
|
||||
return message instanceof HDUMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FilterElement<?>> getFilterElements()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,12 +18,12 @@
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.p25.message.filter;
|
||||
package io.github.dsheirer.module.decode.p25.phase1.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.packet.PacketMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.PacketMessage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDUMessage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class LDUMessageFilter extends Filter<IMessage>
|
||||
{
|
||||
public LDUMessageFilter()
|
||||
{
|
||||
super("Link Data Unit");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passes(IMessage message)
|
||||
{
|
||||
return mEnabled && canProcess(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(IMessage message)
|
||||
{
|
||||
return message instanceof LDUMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FilterElement<?>> getFilterElements()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.FilterSet;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.message.SyncLossMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.P25Message;
|
||||
|
||||
public class P25MessageFilterSet extends FilterSet<IMessage>
|
||||
{
|
||||
public P25MessageFilterSet()
|
||||
{
|
||||
super("P25 Message Filter");
|
||||
|
||||
addFilter(new AMBTCMessageFilter());
|
||||
addFilter(new HDUMessageFilter());
|
||||
addFilter(new IPPacketMessageFilter());
|
||||
addFilter(new LDUMessageFilter());
|
||||
addFilter(new PDUMessageFilter());
|
||||
addFilter(new SNDCPMessageFilter());
|
||||
addFilter(new SyncLossMessageFilter());
|
||||
addFilter(new TDUMessageFilter());
|
||||
addFilter(new TDULCMessageFilter());
|
||||
addFilter(new TSBKMessageFilterSet());
|
||||
addFilter(new UMBTCMessageFilter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(IMessage message)
|
||||
{
|
||||
return message instanceof P25Message || message instanceof SyncLossMessage;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,30 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.filter;
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.PDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,12 +18,12 @@
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.p25.message.filter;
|
||||
package io.github.dsheirer.module.decode.p25.phase1.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp.SNDCPMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPMessage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,7 +18,7 @@
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.p25.message.filter;
|
||||
package io.github.dsheirer.module.decode.p25.phase1.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDULinkControlMessage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TDULCMessageFilter extends Filter<IMessage>
|
||||
{
|
||||
public TDULCMessageFilter()
|
||||
{
|
||||
super("TDU Terminator Data Unit with Link Control");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passes(IMessage message)
|
||||
{
|
||||
return mEnabled && canProcess(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(IMessage message)
|
||||
{
|
||||
return message instanceof TDULinkControlMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FilterElement<?>> getFilterElements()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDUMessage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TDUMessageFilter extends Filter<IMessage>
|
||||
{
|
||||
public TDUMessageFilter()
|
||||
{
|
||||
super("TDU Terminator Data Unit");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passes(IMessage message)
|
||||
{
|
||||
return mEnabled && canProcess(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess(IMessage message)
|
||||
{
|
||||
return message instanceof TDUMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FilterElement<?>> getFilterElements()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,31 @@
|
||||
package io.github.dsheirer.module.decode.p25.message.filter;
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.filter.FilterSet;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.TSBKMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.TSBKMessage;
|
||||
import io.github.dsheirer.module.decode.p25.reference.Vendor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,12 +18,12 @@
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.p25.message.filter;
|
||||
package io.github.dsheirer.module.decode.p25.phase1.message.filter;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.pdu.umbtc.UMBTCMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.umbtc.UMBTCMessage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -1,27 +1,33 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.message.hdu;
|
||||
*/
|
||||
package io.github.dsheirer.module.decode.p25.phase1.message.hdu;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import io.github.dsheirer.edac.Golay18;
|
||||
import io.github.dsheirer.edac.ReedSolomon_63_47_17;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.p25.message.P25Message;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.P25Message;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -79,9 +85,9 @@ public class HDUMessage extends P25Message
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataUnitID getDUID()
|
||||
public P25P1DataUnitID getDUID()
|
||||
{
|
||||
return DataUnitID.HEADER_DATA_UNIT;
|
||||
return P25P1DataUnitID.HEADER_DATA_UNIT;
|
||||
}
|
||||
|
||||
public HeaderData getHeaderData()
|
||||
@@ -188,7 +194,7 @@ public class HDUMessage extends P25Message
|
||||
else
|
||||
{
|
||||
//If we corrected any bit errors, update the original message with the bit error count
|
||||
for(int x = 0; x < 23; x++)
|
||||
for(int x = 0; x <= 35; x++)
|
||||
{
|
||||
if(output[x] != input[x])
|
||||
{
|
||||
@@ -1,27 +1,30 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* 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.
|
||||
* * ******************************************************************************
|
||||
* * 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* 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.message.hdu;
|
||||
package io.github.dsheirer.module.decode.p25.phase1.message.hdu;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.encryption.APCO25EncryptionKey;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup;
|
||||
import io.github.dsheirer.module.decode.p25.reference.Encryption;
|
||||
@@ -130,8 +133,8 @@ public class HeaderData
|
||||
{
|
||||
if(mEncryptionKey == null && isEncryptedAudio())
|
||||
{
|
||||
mEncryptionKey = APCO25EncryptionKey.create(getMessage().getInt(ALGORITHM_ID),
|
||||
getMessage().getInt(KEY_ID));
|
||||
mEncryptionKey = EncryptionKeyIdentifier.create(APCO25EncryptionKey.create(getMessage().getInt(ALGORITHM_ID),
|
||||
getMessage().getInt(KEY_ID)));
|
||||
}
|
||||
|
||||
return mEncryptionKey;
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,7 +18,7 @@
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.p25.message.lc;
|
||||
package io.github.dsheirer.module.decode.p25.phase1.message.lc;
|
||||
|
||||
import io.github.dsheirer.module.decode.p25.reference.Vendor;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,7 +18,7 @@
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.p25.message.lc;
|
||||
package io.github.dsheirer.module.decode.p25.phase1.message.lc;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,43 +18,43 @@
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.module.decode.p25.message.lc;
|
||||
package io.github.dsheirer.module.decode.p25.phase1.message.lc;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.motorola.LCMotorolaPatchGroupAdd;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.motorola.LCMotorolaPatchGroupDelete;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.motorola.LCMotorolaPatchGroupVoiceChannelUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.motorola.LCMotorolaPatchGroupVoiceChannelUser;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.motorola.LCMotorolaTalkComplete;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.motorola.LCMotorolaUnknownOpcode;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCAdjacentSiteStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCAdjacentSiteStatusBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCCallAlert;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCCallTermination;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCExtendedFunctionCommand;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCFrequencyBandUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCFrequencyBandUpdateExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCGroupAffiliationQuery;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCGroupVoiceChannelUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCGroupVoiceChannelUpdateExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCGroupVoiceChannelUser;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCMessageUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCNetworkStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCNetworkStatusBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCProtectionParameterBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCRFSSStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCRFSSStatusBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCSecondaryControlChannelBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCSecondaryControlChannelBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCStatusQuery;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCStatusUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCSystemServiceBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCTelephoneInterconnectAnswerRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCTelephoneInterconnectVoiceChannelUser;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCUnitAuthenticationCommand;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCUnitRegistrationCommand;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCUnitToUnitAnswerRequest;
|
||||
import io.github.dsheirer.module.decode.p25.message.lc.standard.LCUnitToUnitVoiceChannelUser;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaPatchGroupAdd;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaPatchGroupDelete;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaPatchGroupVoiceChannelUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaPatchGroupVoiceChannelUser;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaTalkComplete;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaUnknownOpcode;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCAdjacentSiteStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCAdjacentSiteStatusBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCCallAlert;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCCallTermination;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCExtendedFunctionCommand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCFrequencyBandUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCFrequencyBandUpdateExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupAffiliationQuery;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupVoiceChannelUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupVoiceChannelUpdateExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupVoiceChannelUser;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCMessageUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCNetworkStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCNetworkStatusBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCProtectionParameterBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCRFSSStatusBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCRFSSStatusBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCSecondaryControlChannelBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCSecondaryControlChannelBroadcastExplicit;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCStatusQuery;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCStatusUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCSystemServiceBroadcast;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCTelephoneInterconnectAnswerRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCTelephoneInterconnectVoiceChannelUser;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCUnitAuthenticationCommand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCUnitRegistrationCommand;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCUnitToUnitAnswerRequest;
|
||||
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCUnitToUnitVoiceChannelUser;
|
||||
|
||||
/**
|
||||
* Factory class for creating link control word (LCW) message parsers.
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* 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.message.lc;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Unknown link control word.
|
||||
*/
|
||||
public class UnknownLinkControlWord extends LinkControlWord
|
||||
{
|
||||
/**
|
||||
* Constructs a Link Control Word from the binary message sequence.
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
public UnknownLinkControlWord(BinaryMessage message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getIdentifiers()
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getMessageStub());
|
||||
sb.append(" UNKNOWN/UNRECOGNIZED OPCODE");
|
||||
sb.append(" MSG:").append(getMessage().toHexString());
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user