#296 APCO25 Phase II Decoder Implementation (#589)

P25 Phase 2 Decoder implementation.
This commit is contained in:
Denny Sheirer
2019-11-17 06:56:52 -05:00
committed by GitHub
parent d5b802e794
commit f934676bd0
561 changed files with 35609 additions and 6215 deletions

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -1,21 +1,23 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* * ******************************************************************************
* * Copyright (C) 2014-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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -1,21 +1,23 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* * ******************************************************************************
* * Copyright (C) 2014-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;
}
}
}

View File

@@ -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();
}

View File

@@ -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:

View File

@@ -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)

View File

@@ -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();
}

View File

@@ -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;
/**

View File

@@ -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
{

View File

@@ -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();
}

View File

@@ -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();

View File

@@ -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>

View File

@@ -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();

View File

@@ -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>

View File

@@ -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();

View File

@@ -1,20 +1,24 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
/*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* * ******************************************************************************
* * 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;
}
}

View File

@@ -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);
}

View File

@@ -1,21 +1,23 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* * ******************************************************************************
* * Copyright (C) 2014-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));
}
}

View File

@@ -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:

View File

@@ -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;

View File

@@ -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 );
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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;
}
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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());
}
}

View File

@@ -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>
{

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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)
{
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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);
}
/**

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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()
{
}

View File

@@ -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);

View File

@@ -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();
}
}

View File

@@ -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()
{
}

View File

@@ -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;

View File

@@ -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,

View File

@@ -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();
}
}

View File

@@ -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()
{
}

View File

@@ -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");

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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
{

View File

@@ -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;

View File

@@ -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()
{

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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])
{

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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.

View File

@@ -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();
}
}

View File

@@ -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.motorola;
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.identifier.Identifier;

Some files were not shown because too many files have changed in this diff Show More