mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
Updates pull request from Roman Tsypuk to convert the build system from
ant to gradle. Removes linux and windows application launch scripts and produces an executable jar with all resources included.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.ltrnet;
|
||||
|
||||
import io.github.dsheirer.message.MessageDirection;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
public class DecodeConfigLTRNet extends DecodeConfiguration
|
||||
{
|
||||
private MessageDirection mMessageDirection = MessageDirection.OSW;
|
||||
|
||||
public DecodeConfigLTRNet()
|
||||
{
|
||||
super( DecoderType.LTR_NET );
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "direction" )
|
||||
public MessageDirection getMessageDirection()
|
||||
{
|
||||
return mMessageDirection;
|
||||
}
|
||||
|
||||
public void setMessageDirection( MessageDirection direction )
|
||||
{
|
||||
mMessageDirection = direction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.ltrnet;
|
||||
|
||||
import io.github.dsheirer.alias.Alias;
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.event.CallEvent;
|
||||
|
||||
public class LTRCallEvent extends CallEvent
|
||||
{
|
||||
private String mChannel;
|
||||
private long mFrequency;
|
||||
|
||||
public LTRCallEvent( DecoderType type,
|
||||
CallEventType callEventType,
|
||||
AliasList aliasList,
|
||||
String fromID,
|
||||
String toID,
|
||||
String channel,
|
||||
long frequency,
|
||||
String details )
|
||||
{
|
||||
super( type, callEventType, aliasList, fromID, toID, details );
|
||||
|
||||
mChannel = channel;
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the message's talkgroup matches this call event. Counts the
|
||||
* number of messages that match this call event to use in determining if
|
||||
* a call event is valid or an isolated (errant) message.
|
||||
*
|
||||
* See: isValid()
|
||||
*/
|
||||
public boolean isMatchingTalkgroup( LTRNetMessage message )
|
||||
{
|
||||
String talkgroup = message.getTalkgroupID();
|
||||
|
||||
if( talkgroup != null && getToID() != null &&
|
||||
talkgroup.contentEquals( getToID() ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return isMatchingTalkgroup( message.getTalkgroupID() );
|
||||
}
|
||||
|
||||
public boolean isMatchingTalkgroup( String talkgroup )
|
||||
{
|
||||
return talkgroup != null && getToID() != null && talkgroup.contentEquals( getToID() );
|
||||
}
|
||||
|
||||
private Alias getAlias(String talkgroup )
|
||||
{
|
||||
if( hasAliasList() )
|
||||
{
|
||||
return getAliasList().getTalkgroupAlias( talkgroup );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getFromIDAlias()
|
||||
{
|
||||
if( mCallEventType == CallEventType.CALL ||
|
||||
mCallEventType == CallEventType.REGISTER ||
|
||||
mCallEventType == CallEventType.ID_UNIQUE )
|
||||
{
|
||||
if( hasAliasList() )
|
||||
{
|
||||
try
|
||||
{
|
||||
int radioID = Integer.parseInt( getFromID() );
|
||||
|
||||
return mAliasList.getUniqueID( radioID );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
//Do nothing, we couldn't parse the int radio id value
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( mCallEventType == CallEventType.REGISTER_ESN )
|
||||
{
|
||||
if( hasAliasList() )
|
||||
{
|
||||
return mAliasList.getESNAlias( getFromID() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return getAlias( getFromID() );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getToIDAlias()
|
||||
{
|
||||
return getAlias( getToID() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChannel()
|
||||
{
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
public static class Builder
|
||||
{
|
||||
/* Required parameters */
|
||||
private DecoderType mDecoderType;
|
||||
private CallEventType mCallEventType;
|
||||
|
||||
/* Optional parameters */
|
||||
private AliasList mAliasList;
|
||||
private String mFromID;
|
||||
private String mToID;
|
||||
private String mDetails;
|
||||
private String mChannel;
|
||||
private long mFrequency;
|
||||
|
||||
public Builder( DecoderType decoderType, CallEventType callEventType )
|
||||
{
|
||||
mDecoderType = decoderType;
|
||||
mCallEventType = callEventType;
|
||||
}
|
||||
|
||||
public Builder aliasList( AliasList aliasList )
|
||||
{
|
||||
mAliasList = aliasList;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder from( String val )
|
||||
{
|
||||
mFromID = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder channel( String channel )
|
||||
{
|
||||
mChannel = channel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder details( String details )
|
||||
{
|
||||
mDetails = details;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder frequency( long frequency )
|
||||
{
|
||||
mFrequency = frequency;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder to( String toID )
|
||||
{
|
||||
mToID = toID;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LTRCallEvent build()
|
||||
{
|
||||
return new LTRCallEvent( this );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for the builder
|
||||
*/
|
||||
private LTRCallEvent( Builder builder )
|
||||
{
|
||||
this( builder.mDecoderType,
|
||||
builder.mCallEventType,
|
||||
builder.mAliasList,
|
||||
builder.mFromID,
|
||||
builder.mToID,
|
||||
builder.mChannel,
|
||||
builder.mFrequency,
|
||||
builder.mDetails );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.ltrnet;
|
||||
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.bits.MessageFramer;
|
||||
import io.github.dsheirer.bits.SyncPattern;
|
||||
import io.github.dsheirer.dsp.fsk.LTRFSKDecoder;
|
||||
import io.github.dsheirer.instrument.Instrumentable;
|
||||
import io.github.dsheirer.instrument.tap.Tap;
|
||||
import io.github.dsheirer.instrument.tap.TapGroup;
|
||||
import io.github.dsheirer.message.MessageDirection;
|
||||
import io.github.dsheirer.module.decode.Decoder;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.real.IUnFilteredRealBufferListener;
|
||||
import io.github.dsheirer.sample.real.RealBuffer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
public class LTRNetDecoder extends Decoder
|
||||
implements IUnFilteredRealBufferListener, Instrumentable
|
||||
{
|
||||
public static final int LTR_STANDARD_MESSAGE_LENGTH = 40;
|
||||
private LTRFSKDecoder mLTRFSKDecoder;
|
||||
private MessageFramer mLTRMessageFramer;
|
||||
private LTRNetMessageProcessor mLTRMessageProcessor;
|
||||
|
||||
private List<TapGroup> mAvailableTaps;
|
||||
|
||||
/**
|
||||
* LTR-Net Decoder. Decodes unfiltered (e.g. demodulated but with no DC or
|
||||
* audio filtering) samples and produces LTR-Net messages.
|
||||
*/
|
||||
public LTRNetDecoder( DecodeConfigLTRNet config, AliasList aliasList )
|
||||
{
|
||||
mLTRFSKDecoder = new LTRFSKDecoder();
|
||||
|
||||
|
||||
if( config.getMessageDirection() == MessageDirection.OSW )
|
||||
{
|
||||
mLTRMessageFramer =
|
||||
new MessageFramer( SyncPattern.LTR_STANDARD_OSW.getPattern(),
|
||||
LTR_STANDARD_MESSAGE_LENGTH );
|
||||
}
|
||||
else
|
||||
{
|
||||
mLTRMessageFramer =
|
||||
new MessageFramer( SyncPattern.LTR_STANDARD_ISW.getPattern(),
|
||||
LTR_STANDARD_MESSAGE_LENGTH );
|
||||
}
|
||||
|
||||
mLTRFSKDecoder.addListener( mLTRMessageFramer );
|
||||
|
||||
mLTRMessageProcessor = new LTRNetMessageProcessor(
|
||||
config.getMessageDirection(), aliasList );
|
||||
|
||||
mLTRMessageFramer.addMessageListener( mLTRMessageProcessor );
|
||||
|
||||
mLTRMessageProcessor.setMessageListener( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecoderType getDecoderType()
|
||||
{
|
||||
return DecoderType.LTR_NET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<RealBuffer> getUnFilteredRealBufferListener()
|
||||
{
|
||||
return mLTRFSKDecoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TapGroup> getTapGroups()
|
||||
{
|
||||
if( mAvailableTaps == null )
|
||||
{
|
||||
mAvailableTaps = new ArrayList<TapGroup>();
|
||||
|
||||
mAvailableTaps.addAll( mLTRFSKDecoder.getTapGroups() );
|
||||
}
|
||||
|
||||
return mAvailableTaps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerTap( Tap tap )
|
||||
{
|
||||
mLTRFSKDecoder.registerTap( tap );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterTap( Tap tap )
|
||||
{
|
||||
mLTRFSKDecoder.unregisterTap( tap );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
mLTRMessageFramer.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start( ScheduledExecutorService executor )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.ltrnet;
|
||||
|
||||
import io.github.dsheirer.controller.channel.Channel;
|
||||
import io.github.dsheirer.gui.editor.Editor;
|
||||
import io.github.dsheirer.gui.editor.EditorValidationException;
|
||||
import io.github.dsheirer.gui.editor.ValidatingEditor;
|
||||
import io.github.dsheirer.message.MessageDirection;
|
||||
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class LTRNetDecoderEditor extends ValidatingEditor<Channel>
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private JCheckBox mAFC;
|
||||
private JSlider mAFCMaximumCorrection;
|
||||
private JComboBox<MessageDirection> mComboDirection;
|
||||
|
||||
public LTRNetDecoderEditor()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "insets 0 0 0 0,wrap 4", "[right][grow,fill][right][grow,fill]", "" ) );
|
||||
|
||||
mAFC = new JCheckBox( "AFC: 3000 Hz" );
|
||||
mAFC.setEnabled( false );
|
||||
mAFC.setToolTipText( "AFC automatically adjusts the center frequency of the channel to "
|
||||
+ "correct/compensate for inaccuracies and frequency drift in the tuner" );
|
||||
mAFC.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent arg0 )
|
||||
{
|
||||
setModified( true );
|
||||
|
||||
if( mAFC.isSelected() && !mAFCMaximumCorrection.isEnabled() )
|
||||
{
|
||||
mAFCMaximumCorrection.setEnabled( true );
|
||||
}
|
||||
else if( !mAFC.isSelected() && mAFCMaximumCorrection.isEnabled() )
|
||||
{
|
||||
mAFCMaximumCorrection.setEnabled( false );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
add( mAFC );
|
||||
|
||||
mAFCMaximumCorrection = new JSlider( 0, 7000, 3000 );
|
||||
mAFCMaximumCorrection.setEnabled( false );
|
||||
mAFCMaximumCorrection.setToolTipText( "Maximum AFC frequency correction (0 - 15kHz)" );
|
||||
mAFCMaximumCorrection.setMajorTickSpacing( 2000 );
|
||||
mAFCMaximumCorrection.setMinorTickSpacing( 1000 );
|
||||
mAFCMaximumCorrection.setPaintTicks( true );
|
||||
|
||||
mAFCMaximumCorrection.addChangeListener( new ChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent e )
|
||||
{
|
||||
mAFC.setText( "AFC: " + mAFCMaximumCorrection.getValue() + " Hz" );
|
||||
setModified( true );
|
||||
}
|
||||
} );
|
||||
add( mAFCMaximumCorrection );
|
||||
|
||||
mComboDirection = new JComboBox<MessageDirection>();
|
||||
mComboDirection.setModel( new DefaultComboBoxModel<MessageDirection>( MessageDirection.values() ) );
|
||||
mComboDirection.setSelectedItem( MessageDirection.OSW );
|
||||
mComboDirection.setEnabled( false );
|
||||
mComboDirection.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
setModified( true );
|
||||
}
|
||||
} );
|
||||
|
||||
add( new JLabel( "Format:" ) );
|
||||
add( mComboDirection );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate( Editor<Channel> editor ) throws EditorValidationException
|
||||
{
|
||||
//No validation
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setItem( Channel item )
|
||||
{
|
||||
super.setItem( item );
|
||||
|
||||
if( hasItem() )
|
||||
{
|
||||
mAFC.setEnabled( true );
|
||||
mComboDirection.setEnabled( true );
|
||||
|
||||
DecodeConfiguration config = getItem().getDecodeConfiguration();
|
||||
|
||||
if( config instanceof DecodeConfigLTRNet )
|
||||
{
|
||||
DecodeConfigLTRNet ltr = (DecodeConfigLTRNet)config;
|
||||
mComboDirection.setSelectedItem( ltr.getMessageDirection() );
|
||||
mAFC.setSelected( ltr.isAFCEnabled() );
|
||||
mAFCMaximumCorrection.setValue( ltr.getAFCMaximumCorrection() );
|
||||
mAFCMaximumCorrection.setEnabled( ltr.isAFCEnabled() );
|
||||
|
||||
setModified( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
mComboDirection.setSelectedItem( MessageDirection.OSW );
|
||||
mAFC.setSelected( false );
|
||||
mAFCMaximumCorrection.setValue( DecodeConfiguration.DEFAULT_AFC_MAX_CORRECTION );
|
||||
mAFCMaximumCorrection.setEnabled( false );
|
||||
|
||||
setModified( true );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mAFC.setEnabled( false );
|
||||
mComboDirection.setEnabled( false );
|
||||
setModified( false );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
if( hasItem() && isModified() )
|
||||
{
|
||||
DecodeConfigLTRNet ltr = new DecodeConfigLTRNet();
|
||||
|
||||
ltr.setAFC( mAFC.isSelected() );
|
||||
ltr.setAFCMaximumCorrection( mAFCMaximumCorrection.getValue() );
|
||||
ltr.setMessageDirection( (MessageDirection)mComboDirection.getSelectedItem() );
|
||||
|
||||
getItem().setDecodeConfiguration( ltr );
|
||||
}
|
||||
|
||||
setModified( false );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,798 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.ltrnet;
|
||||
|
||||
import io.github.dsheirer.alias.Alias;
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.alias.id.AliasIDType;
|
||||
import io.github.dsheirer.channel.metadata.AliasedIntegerAttributeMonitor;
|
||||
import io.github.dsheirer.channel.metadata.AliasedStringAttributeMonitor;
|
||||
import io.github.dsheirer.channel.metadata.Attribute;
|
||||
import io.github.dsheirer.channel.metadata.AttributeChangeRequest;
|
||||
import io.github.dsheirer.channel.state.DecoderState;
|
||||
import io.github.dsheirer.channel.state.DecoderStateEvent;
|
||||
import io.github.dsheirer.channel.state.DecoderStateEvent.Event;
|
||||
import io.github.dsheirer.channel.state.State;
|
||||
import io.github.dsheirer.message.Message;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.event.CallEvent;
|
||||
import io.github.dsheirer.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
public class LTRNetDecoderState extends DecoderState
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(LTRNetDecoderState.class);
|
||||
|
||||
private DecimalFormat mDecimalFormatter = new DecimalFormat("0.00000");
|
||||
|
||||
private TreeSet<String> mTalkgroups = new TreeSet<String>();
|
||||
private TreeSet<String> mTalkgroupsFirstHeard = new TreeSet<String>();
|
||||
private TreeSet<String> mESNs = new TreeSet<String>();
|
||||
private TreeSet<Integer> mUniqueIDs = new TreeSet<Integer>();
|
||||
private TreeSet<String> mNeighborIDs = new TreeSet<String>();
|
||||
private TreeSet<String> mSiteIDs = new TreeSet<String>();
|
||||
private HashMap<Integer,Long> mReceiveFrequencies =
|
||||
new HashMap<Integer,Long>();
|
||||
private HashMap<Integer,Long> mTransmitFrequencies =
|
||||
new HashMap<Integer,Long>();
|
||||
private HashMap<Integer,String> mActiveCalls = new HashMap<Integer,String>();
|
||||
|
||||
private AliasedStringAttributeMonitor mToAttribute;
|
||||
private AliasedIntegerAttributeMonitor mFromUIDAttribute;
|
||||
private AliasedStringAttributeMonitor mESNAttribute;
|
||||
private String mMessage;
|
||||
private String mMessageType;
|
||||
private int mChannelNumber;
|
||||
private long mFrequency = 0;
|
||||
|
||||
public LTRNetDecoderState(AliasList aliasList)
|
||||
{
|
||||
super(aliasList);
|
||||
|
||||
mToAttribute = new AliasedStringAttributeMonitor(Attribute.PRIMARY_ADDRESS_TO,
|
||||
getAttributeChangeRequestListener(), getAliasList(), AliasIDType.TALKGROUP);
|
||||
mToAttribute.addIllegalValue("0-00-000");
|
||||
|
||||
mFromUIDAttribute = new AliasedIntegerAttributeMonitor(Attribute.PRIMARY_ADDRESS_TO,
|
||||
getAttributeChangeRequestListener(), getAliasList(), AliasIDType.LTR_NET_UID);
|
||||
|
||||
mESNAttribute = new AliasedStringAttributeMonitor(Attribute.SECONDARY_ADDRESS_FROM,
|
||||
getAttributeChangeRequestListener(), getAliasList(), AliasIDType.ESN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecoderType getDecoderType()
|
||||
{
|
||||
return DecoderType.LTR_NET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(Message message)
|
||||
{
|
||||
if(message.isValid())
|
||||
{
|
||||
State state = State.IDLE;
|
||||
|
||||
if(message instanceof LTRNetOSWMessage)
|
||||
{
|
||||
LTRNetOSWMessage ltr = (LTRNetOSWMessage) message;
|
||||
|
||||
switch(ltr.getMessageType())
|
||||
{
|
||||
case CA_ENDD:
|
||||
if(mChannelNumber == 0)
|
||||
{
|
||||
setChannelNumber(ltr.getChannel());
|
||||
}
|
||||
|
||||
/* Process FCC Station ID Events */
|
||||
if(ltr.getGroup() == 254)
|
||||
{
|
||||
if(mCurrentCallEvent == null ||
|
||||
mCurrentCallEvent.getCallEventType() !=
|
||||
CallEvent.CallEventType.STATION_ID)
|
||||
{
|
||||
mCurrentCallEvent = new LTRCallEvent.Builder(
|
||||
DecoderType.LTR_NET, CallEvent.CallEventType.STATION_ID)
|
||||
.aliasList(getAliasList())
|
||||
.channel(String.valueOf(mChannelNumber))
|
||||
.frequency(mFrequency)
|
||||
.to(ltr.getTalkgroupID())
|
||||
.build();
|
||||
|
||||
broadcast(mCurrentCallEvent);
|
||||
|
||||
broadcast(new DecoderStateEvent(this, Event.START, State.DATA));
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.DATA));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
processCallEndMessage(ltr);
|
||||
}
|
||||
break;
|
||||
case CA_STRT:
|
||||
if(mChannelNumber == 0)
|
||||
{
|
||||
setChannelNumber(ltr.getChannel());
|
||||
}
|
||||
|
||||
/* If the call event channel matches our current channel
|
||||
* then it's a call, otherwise it's a call detect. */
|
||||
if(ltr.getChannel() == mChannelNumber)
|
||||
{
|
||||
processCallMessage(ltr);
|
||||
}
|
||||
else
|
||||
{
|
||||
processCallDetectMessage(ltr);
|
||||
}
|
||||
|
||||
break;
|
||||
case SY_IDLE:
|
||||
if(mChannelNumber != ltr.getChannel())
|
||||
{
|
||||
setChannelNumber(ltr.getChannel());
|
||||
}
|
||||
break;
|
||||
case MA_CHNH:
|
||||
break;
|
||||
case MA_CHNL:
|
||||
break;
|
||||
case FQ_RXHI:
|
||||
case FQ_RXLO:
|
||||
if(ltr.getFrequency() > 0)
|
||||
{
|
||||
mReceiveFrequencies.put(ltr.getHomeRepeater(), ltr.getFrequency());
|
||||
}
|
||||
break;
|
||||
case FQ_TXHI:
|
||||
case FQ_TXLO:
|
||||
if(ltr.getFrequency() > 0)
|
||||
{
|
||||
mTransmitFrequencies.put(ltr.getHomeRepeater(), ltr.getFrequency());
|
||||
}
|
||||
break;
|
||||
case ID_NBOR:
|
||||
String neighborID = ltr.getNeighborID();
|
||||
|
||||
if(neighborID != null)
|
||||
{
|
||||
mNeighborIDs.add(neighborID);
|
||||
}
|
||||
break;
|
||||
case ID_UNIQ:
|
||||
state = State.DATA;
|
||||
|
||||
int uniqueID = ltr.getRadioUniqueID();
|
||||
|
||||
if(uniqueID != LTRNetOSWMessage.INT_NULL_VALUE)
|
||||
{
|
||||
mUniqueIDs.add(uniqueID);
|
||||
}
|
||||
|
||||
if(getCurrentLTRCallEvent() == null)
|
||||
{
|
||||
mCurrentCallEvent = new LTRCallEvent.Builder(
|
||||
DecoderType.LTR_NET, CallEvent.CallEventType.REGISTER)
|
||||
.aliasList(getAliasList())
|
||||
.channel(String.valueOf(mChannelNumber))
|
||||
.frequency(mFrequency)
|
||||
.from(String.valueOf(uniqueID))
|
||||
.build();
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurrentCallEvent.setFromID(
|
||||
String.valueOf(ltr.getRadioUniqueID()));
|
||||
mCurrentCallEvent.setDetails("Unique ID");
|
||||
|
||||
broadcast(mCurrentCallEvent);
|
||||
}
|
||||
|
||||
mFromUIDAttribute.process(uniqueID);
|
||||
break;
|
||||
case ID_SITE:
|
||||
String siteID = ltr.getSiteID();
|
||||
|
||||
if(siteID != null)
|
||||
{
|
||||
mSiteIDs.add(siteID);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(message instanceof LTRNetISWMessage)
|
||||
{
|
||||
LTRNetISWMessage ltr = ((LTRNetISWMessage) message);
|
||||
|
||||
switch(ltr.getMessageType())
|
||||
{
|
||||
case CA_STRT:
|
||||
processCallMessage(ltr);
|
||||
break;
|
||||
case CA_ENDD:
|
||||
processCallEndMessage(ltr);
|
||||
break;
|
||||
case ID_ESNH:
|
||||
case ID_ESNL:
|
||||
state = State.DATA;
|
||||
|
||||
String esn = ltr.getESN();
|
||||
|
||||
if(!esn.contains("xxxx"))
|
||||
{
|
||||
mESNs.add(ltr.getESN());
|
||||
}
|
||||
|
||||
setMessageType("ESN");
|
||||
mESNAttribute.process(ltr.getESN());
|
||||
|
||||
broadcast(new DecoderStateEvent(this, Event.DECODE, State.DATA));
|
||||
|
||||
if(mCurrentCallEvent == null)
|
||||
{
|
||||
mCurrentCallEvent = new LTRCallEvent.Builder(
|
||||
DecoderType.LTR_NET, CallEvent.CallEventType.REGISTER_ESN)
|
||||
.aliasList(getAliasList())
|
||||
.details("ESN:" + ltr.getESN())
|
||||
.frequency(mFrequency)
|
||||
.from(ltr.getESN())
|
||||
.build();
|
||||
|
||||
broadcast(mCurrentCallEvent);
|
||||
}
|
||||
|
||||
break;
|
||||
case ID_UNIQ:
|
||||
state = State.DATA;
|
||||
|
||||
int uniqueid = ltr.getRadioUniqueID();
|
||||
|
||||
if(uniqueid != LTRNetISWMessage.INT_NULL_VALUE)
|
||||
{
|
||||
mUniqueIDs.add(uniqueid);
|
||||
|
||||
setMessageType("REGISTER UID");
|
||||
mFromUIDAttribute.process(uniqueid);
|
||||
|
||||
if(getCurrentLTRCallEvent() == null)
|
||||
{
|
||||
mCurrentCallEvent = new LTRCallEvent.Builder(
|
||||
DecoderType.LTR_NET, CallEvent.CallEventType.REGISTER)
|
||||
.aliasList(getAliasList())
|
||||
.channel(String.valueOf(mChannelNumber))
|
||||
.frequency(mFrequency)
|
||||
.from(String.valueOf(uniqueid))
|
||||
.build();
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurrentCallEvent.setFromID(
|
||||
String.valueOf(ltr.getRadioUniqueID()));
|
||||
mCurrentCallEvent.setDetails("Unique ID");
|
||||
|
||||
broadcast(mCurrentCallEvent);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LTRCallEvent getCurrentLTRCallEvent()
|
||||
{
|
||||
if(mCurrentCallEvent != null)
|
||||
{
|
||||
return (LTRCallEvent) mCurrentCallEvent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivitySummary()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("Activity Summary\n");
|
||||
sb.append("Decoder:\tLTR-Net\n\n");
|
||||
|
||||
if(mSiteIDs.isEmpty())
|
||||
{
|
||||
sb.append("Site:\tUnknown\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Iterator<String> it = mSiteIDs.iterator();
|
||||
|
||||
while(it.hasNext())
|
||||
{
|
||||
sb.append("Site:\t");
|
||||
|
||||
String siteID = it.next();
|
||||
|
||||
sb.append(siteID);
|
||||
|
||||
if(hasAliasList())
|
||||
{
|
||||
Alias siteAlias = getAliasList().getSiteID(String.valueOf(siteID));
|
||||
|
||||
if(siteAlias != null)
|
||||
{
|
||||
sb.append(" ");
|
||||
sb.append(siteAlias.getName());
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\nLCNs (transmit | receive)\n");
|
||||
|
||||
if(mReceiveFrequencies.isEmpty() && mTransmitFrequencies.isEmpty())
|
||||
{
|
||||
sb.append(" None\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int x = 1; x < 21; x++)
|
||||
{
|
||||
long rcv = 0;
|
||||
|
||||
if(mReceiveFrequencies.containsKey(x))
|
||||
{
|
||||
rcv = mReceiveFrequencies.get(x);
|
||||
}
|
||||
|
||||
long xmt = 0;
|
||||
|
||||
if(mTransmitFrequencies.containsKey(x))
|
||||
{
|
||||
xmt = mTransmitFrequencies.get(x);
|
||||
}
|
||||
|
||||
if(rcv > 0 || xmt > 0)
|
||||
{
|
||||
if(x < 10)
|
||||
{
|
||||
sb.append(" ");
|
||||
}
|
||||
|
||||
sb.append(x);
|
||||
sb.append(": ");
|
||||
|
||||
if(xmt == 0)
|
||||
{
|
||||
sb.append("---.-----");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(mDecimalFormatter.format((double) xmt / 1E6d));
|
||||
}
|
||||
sb.append(" | ");
|
||||
|
||||
if(rcv == 0)
|
||||
{
|
||||
sb.append("---.-----");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(mDecimalFormatter.format((double) rcv / 1E6d));
|
||||
}
|
||||
|
||||
if(x == mChannelNumber)
|
||||
{
|
||||
sb.append(" **");
|
||||
}
|
||||
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\nTalkgroups\n");
|
||||
|
||||
if(mTalkgroups.isEmpty())
|
||||
{
|
||||
sb.append(" None\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Iterator<String> it = mTalkgroups.iterator();
|
||||
|
||||
while(it.hasNext())
|
||||
{
|
||||
String tgid = it.next();
|
||||
|
||||
sb.append(" ");
|
||||
sb.append(tgid);
|
||||
sb.append(" ");
|
||||
|
||||
if(hasAliasList())
|
||||
{
|
||||
Alias alias = getAliasList().getTalkgroupAlias(tgid);
|
||||
|
||||
if(alias != null)
|
||||
{
|
||||
sb.append(alias.getName());
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\nRadio Unique IDs\n");
|
||||
|
||||
if(mUniqueIDs.isEmpty())
|
||||
{
|
||||
sb.append(" None\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Iterator<Integer> it = mUniqueIDs.iterator();
|
||||
|
||||
while(it.hasNext())
|
||||
{
|
||||
int uid = it.next();
|
||||
|
||||
sb.append(" ");
|
||||
sb.append(uid);
|
||||
sb.append(" ");
|
||||
|
||||
if(hasAliasList())
|
||||
{
|
||||
Alias alias = getAliasList().getUniqueID(uid);
|
||||
|
||||
if(alias != null)
|
||||
{
|
||||
sb.append(alias.getName());
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\nESNs\n");
|
||||
|
||||
if(mESNs.isEmpty())
|
||||
{
|
||||
sb.append(" None\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Iterator<String> it = mESNs.iterator();
|
||||
|
||||
while(it.hasNext())
|
||||
{
|
||||
String esn = it.next();
|
||||
|
||||
sb.append(" ");
|
||||
sb.append(esn);
|
||||
sb.append(" ");
|
||||
|
||||
if(hasAliasList())
|
||||
{
|
||||
Alias alias = getAliasList().getESNAlias(esn);
|
||||
|
||||
if(alias != null)
|
||||
{
|
||||
sb.append(alias.getName());
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\nNeighbor Sites\n");
|
||||
|
||||
if(mNeighborIDs.isEmpty())
|
||||
{
|
||||
sb.append(" None\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Iterator<String> it = mNeighborIDs.iterator();
|
||||
|
||||
while(it.hasNext())
|
||||
{
|
||||
String neighbor = it.next();
|
||||
|
||||
sb.append(" ");
|
||||
sb.append(neighbor);
|
||||
sb.append(" ");
|
||||
|
||||
if(hasAliasList())
|
||||
{
|
||||
Alias alias = getAliasList().getSiteID(String.valueOf(neighbor));
|
||||
|
||||
if(alias != null)
|
||||
{
|
||||
sb.append(alias.getName());
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call Detect - current channel messages indicate a call on another channel
|
||||
*/
|
||||
private void processCallDetectMessage(LTRNetMessage message)
|
||||
{
|
||||
if(!mActiveCalls.containsKey(message.getChannel()) ||
|
||||
!mActiveCalls.get(message.getChannel()).contentEquals(message.getTalkgroupID()))
|
||||
{
|
||||
mActiveCalls.put(message.getChannel(), message.getTalkgroupID());
|
||||
|
||||
int channel = message.getChannel();
|
||||
|
||||
long frequency = 0;
|
||||
|
||||
if(mTransmitFrequencies.containsKey(channel))
|
||||
{
|
||||
frequency = mTransmitFrequencies.get(channel);
|
||||
}
|
||||
|
||||
broadcast(new LTRCallEvent.Builder(DecoderType.LTR_NET, CallEvent.CallEventType.CALL_DETECT)
|
||||
.aliasList(getAliasList())
|
||||
.channel(String.valueOf(message.getChannel()))
|
||||
.frequency(frequency)
|
||||
.to(message.getTalkgroupID())
|
||||
.build());
|
||||
}
|
||||
|
||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.IDLE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the talkgroup is different than the talkgroup specified in
|
||||
* the current call event
|
||||
*/
|
||||
private boolean isDifferentTalkgroup(String talkgroup)
|
||||
{
|
||||
return talkgroup != null &&
|
||||
mCurrentCallEvent != null &&
|
||||
mCurrentCallEvent.getToID() != null &&
|
||||
!mCurrentCallEvent.getToID().contentEquals(talkgroup);
|
||||
}
|
||||
|
||||
private boolean isValidTalkgroup(String talkgroup)
|
||||
{
|
||||
return talkgroup != null && !talkgroup.matches("0-00-000");
|
||||
}
|
||||
|
||||
private void processCallMessage(LTRNetMessage message)
|
||||
{
|
||||
int group = message.getGroup();
|
||||
|
||||
/* Process call registration */
|
||||
if(group == 253)
|
||||
{
|
||||
setMessageType("REGISTER");
|
||||
broadcast(new DecoderStateEvent(this, Event.START, State.DATA));
|
||||
}
|
||||
/* Process call */
|
||||
else
|
||||
{
|
||||
String talkgroup = message.getTalkgroupID();
|
||||
|
||||
if(isValidTalkgroup(talkgroup))
|
||||
{
|
||||
mToAttribute.process(talkgroup);
|
||||
|
||||
final LTRCallEvent current = getCurrentLTRCallEvent();
|
||||
|
||||
//If this is a new call or the talkgroup is different from the current call, create a new call event
|
||||
if(current == null || isDifferentTalkgroup(talkgroup))
|
||||
{
|
||||
/* Invalidate the current call */
|
||||
if(current != null)
|
||||
{
|
||||
current.setValid(false);
|
||||
broadcast(current);
|
||||
}
|
||||
|
||||
/* A talkgroup must be seen at least once before it will be added
|
||||
* to the mTalkgroups list that is used in the activity summary,
|
||||
* so that we don't pollute the summary with one-off error talkgroups */
|
||||
if(mTalkgroupsFirstHeard.contains(talkgroup))
|
||||
{
|
||||
mTalkgroups.add(talkgroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
mTalkgroupsFirstHeard.add(talkgroup);
|
||||
}
|
||||
|
||||
CallEvent callEvent = new LTRCallEvent.Builder(DecoderType.LTR_NET, CallEvent.CallEventType.CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(String.valueOf(message.getChannel()))
|
||||
.frequency(mFrequency)
|
||||
.to(message.getTalkgroupID())
|
||||
.build();
|
||||
|
||||
broadcast(callEvent);
|
||||
|
||||
mCurrentCallEvent = callEvent;
|
||||
|
||||
broadcast(new DecoderStateEvent(this, Event.START, State.CALL));
|
||||
}
|
||||
|
||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processCallEndMessage(LTRNetMessage message)
|
||||
{
|
||||
if(mCurrentCallEvent != null &&
|
||||
mCurrentCallEvent.getCallEventType() == CallEvent.CallEventType.CALL)
|
||||
{
|
||||
mCurrentCallEvent.setEnd(System.currentTimeMillis());
|
||||
broadcast(mCurrentCallEvent);
|
||||
}
|
||||
|
||||
mCurrentCallEvent = null;
|
||||
|
||||
broadcast(new DecoderStateEvent(this, Event.END, State.FADE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a full reset
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
mChannelNumber = 0;
|
||||
|
||||
mActiveCalls.clear();
|
||||
mESNs.clear();
|
||||
mNeighborIDs.clear();
|
||||
mReceiveFrequencies.clear();
|
||||
mSiteIDs.clear();
|
||||
mTalkgroups.clear();
|
||||
mTransmitFrequencies.clear();
|
||||
mUniqueIDs.clear();
|
||||
|
||||
resetState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the decoder state after a call or other decode event
|
||||
*/
|
||||
private void resetState()
|
||||
{
|
||||
if(mCurrentCallEvent != null && mCurrentCallEvent
|
||||
.getCallEventType() == CallEvent.CallEventType.CALL)
|
||||
{
|
||||
mCurrentCallEvent.end();
|
||||
broadcast(mCurrentCallEvent);
|
||||
}
|
||||
|
||||
mCurrentCallEvent = null;
|
||||
|
||||
mToAttribute.reset();
|
||||
mESNAttribute.reset();
|
||||
mFromUIDAttribute.reset();
|
||||
mMessage = null;
|
||||
mMessageType = null;
|
||||
}
|
||||
|
||||
public String getMessage()
|
||||
{
|
||||
return mMessage;
|
||||
}
|
||||
|
||||
public void setMessage(String message)
|
||||
{
|
||||
if(!StringUtils.isEqual(mMessage, message))
|
||||
{
|
||||
mMessage = message;
|
||||
broadcast(new AttributeChangeRequest<String>(Attribute.MESSAGE, mMessageType));
|
||||
}
|
||||
}
|
||||
|
||||
public String getMessageType()
|
||||
{
|
||||
return mMessageType;
|
||||
}
|
||||
|
||||
private void setMessageType(String messageType)
|
||||
{
|
||||
if(!StringUtils.isEqual(mMessageType, messageType))
|
||||
{
|
||||
mMessageType = messageType;
|
||||
broadcast(new AttributeChangeRequest<String>(Attribute.MESSAGE_TYPE, mMessageType));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasChannelNumber()
|
||||
{
|
||||
return mChannelNumber != 0;
|
||||
}
|
||||
|
||||
public int getChannelNumber()
|
||||
{
|
||||
return mChannelNumber;
|
||||
}
|
||||
|
||||
public void setChannelNumber(int channelNumber)
|
||||
{
|
||||
if(mChannelNumber != channelNumber)
|
||||
{
|
||||
mChannelNumber = channelNumber;
|
||||
broadcast(new AttributeChangeRequest<String>(Attribute.CHANNEL_FREQUENCY_LABEL,
|
||||
"LCN:" + getChannelNumber()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
/* No initialization steps required */
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveDecoderStateEvent(DecoderStateEvent event)
|
||||
{
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case RESET:
|
||||
resetState();
|
||||
break;
|
||||
case SOURCE_FREQUENCY:
|
||||
mFrequency = event.getFrequency();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(ScheduledExecutorService executor)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.ltrnet;
|
||||
|
||||
import io.github.dsheirer.alias.Alias;
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.edac.CRC;
|
||||
import io.github.dsheirer.edac.CRCLTR;
|
||||
import io.github.dsheirer.map.Plottable;
|
||||
import io.github.dsheirer.message.MessageDirection;
|
||||
import io.github.dsheirer.message.MessageType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class LTRNetISWMessage extends LTRNetMessage
|
||||
{
|
||||
private static final int sCHIU_UNIQUE_ID = 24;
|
||||
private static final int sCHIU_ESN_LOW = 27;
|
||||
private static final int sCHIU_ESN_HIGH = 29;
|
||||
|
||||
private static final int sFREE_CALL = 21;
|
||||
private static final int sFREE_END_CALL = 23;
|
||||
private static final int sFREE_REQUEST_ACCESS = 31;
|
||||
|
||||
|
||||
private LTRNetISWMessage mAuxMessage;
|
||||
|
||||
public LTRNetISWMessage( BinaryMessage message, AliasList list )
|
||||
{
|
||||
super( message, MessageDirection.ISW, list );
|
||||
|
||||
/**
|
||||
* If the CRC fails, test for a transmitted CRC of 127 and then check
|
||||
* the Free field for special messages
|
||||
*/
|
||||
if( mCRC == CRC.FAILED_CRC && CRCLTR.getTransmittedChecksum( mMessage ) == 127 )
|
||||
{
|
||||
if( getFree() == sFREE_REQUEST_ACCESS ||
|
||||
getFree() == sFREE_END_CALL )
|
||||
{
|
||||
mCRC = CRC.PASSED;
|
||||
}
|
||||
}
|
||||
|
||||
mMessageType = getMessageType();
|
||||
}
|
||||
|
||||
public void setAuxiliaryMessage( LTRNetISWMessage message )
|
||||
{
|
||||
if( message != null )
|
||||
{
|
||||
mAuxMessage = message;
|
||||
}
|
||||
}
|
||||
|
||||
public String getESN()
|
||||
{
|
||||
if( mMessageType == MessageType.ID_ESNH )
|
||||
{
|
||||
if( mAuxMessage != null &&
|
||||
mAuxMessage.getMessageType() == MessageType.ID_ESNL )
|
||||
{
|
||||
return getESNHigh() + mAuxMessage.getESNLow();
|
||||
}
|
||||
else
|
||||
{
|
||||
return getESNHigh() + "xxxx";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( mAuxMessage != null &&
|
||||
mAuxMessage.getMessageType() == MessageType.ID_ESNH )
|
||||
{
|
||||
return mAuxMessage.getESNHigh() + getESNLow();
|
||||
}
|
||||
else
|
||||
{
|
||||
return "xxxx" + getESNLow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Alias getESNAlias()
|
||||
{
|
||||
if( mAliasList != null )
|
||||
{
|
||||
return mAliasList.getESNAlias( getESN() );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getESNHigh()
|
||||
{
|
||||
int esnHigh = getInt( sSIXTEEN_BITS );
|
||||
|
||||
return String.format("%04X", esnHigh & 0xFFFF );
|
||||
}
|
||||
|
||||
public String getESNLow()
|
||||
{
|
||||
int esnLow = getInt( sSIXTEEN_BITS );
|
||||
|
||||
return String.format("%04X", esnLow & 0xFFFF );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append( mDatestampFormatter.format( new Date( System.currentTimeMillis() ) ) );
|
||||
sb.append( " LTRNet ISW [" );
|
||||
sb.append( mCRC.getAbbreviation() );
|
||||
sb.append( "] " );
|
||||
sb.append( getMessage() );
|
||||
pad( sb, 100 );
|
||||
sb.append( mMessage.toString() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
switch( mMessageType )
|
||||
{
|
||||
case CA_STRT:
|
||||
sb.append( "CALL LCN:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " TG [ " );
|
||||
sb.append( getTalkgroupID() );
|
||||
sb.append( "/" );
|
||||
sb.append( getTalkgroupIDAlias() );
|
||||
sb.append( " ] FREE:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
break;
|
||||
case CA_ENDD:
|
||||
sb.append( "END* AREA:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " LCN:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " TG [" );
|
||||
sb.append( getTalkgroupID() );
|
||||
sb.append( "/" );
|
||||
sb.append( getTalkgroupIDAlias() );
|
||||
sb.append( "] FREE:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
break;
|
||||
case RQ_ACCE:
|
||||
sb.append( "REQUEST ACCESS LCN:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " TG [ " );
|
||||
sb.append( getTalkgroupID() );
|
||||
sb.append( "/" );
|
||||
sb.append( getTalkgroupIDAlias() );
|
||||
sb.append( " ] FREE:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
break;
|
||||
case ID_ESNL:
|
||||
sb.append( "ESN LOW " );
|
||||
sb.append( getESN() );
|
||||
sb.append( "/" );
|
||||
sb.append( getESNAlias() );
|
||||
break;
|
||||
case ID_ESNH:
|
||||
sb.append( "ESN HIGH " );
|
||||
sb.append( getESN() );
|
||||
sb.append( "/" );
|
||||
sb.append( getESNAlias() );
|
||||
break;
|
||||
case ID_UNIQ:
|
||||
sb.append( "RADIO UNIQUE ID " );
|
||||
sb.append( getRadioUniqueID() );
|
||||
|
||||
if( getRadioUniqueIDAlias() != null )
|
||||
{
|
||||
sb.append( "/" );
|
||||
sb.append( getRadioUniqueIDAlias().getName() );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sb.append( "UNKNOWN " );
|
||||
sb.append( getArea() );
|
||||
sb.append( " " );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " " );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( " " );
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
sb.append( " " );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
sb.append( " CRC:" );
|
||||
sb.append( CRCLTR.getTransmittedChecksum( mMessage ) );
|
||||
sb.append( " CALC:" );
|
||||
sb.append( CRCLTR.getCalculatedChecksum( mMessage ) );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public int getRadioUniqueID()
|
||||
{
|
||||
int retVal = INT_NULL_VALUE;
|
||||
|
||||
if( mMessageType == MessageType.ID_UNIQ )
|
||||
{
|
||||
retVal = getInt( sSIXTEEN_BITS );
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public Alias getRadioUniqueIDAlias()
|
||||
{
|
||||
if( mAliasList != null )
|
||||
{
|
||||
return mAliasList.getUniqueID( getRadioUniqueID() );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public MessageType getMessageType()
|
||||
{
|
||||
MessageType retVal = MessageType.UN_KNWN;
|
||||
|
||||
int channel = getChannel();
|
||||
|
||||
if( channel == 31 )
|
||||
{
|
||||
retVal = MessageType.CA_ENDD;
|
||||
}
|
||||
else if( channel > 20 )
|
||||
{
|
||||
switch( channel )
|
||||
{
|
||||
case sCHIU_UNIQUE_ID:
|
||||
retVal = MessageType.ID_UNIQ;
|
||||
break;
|
||||
case sCHIU_ESN_LOW:
|
||||
retVal = MessageType.ID_ESNH;
|
||||
break;
|
||||
case sCHIU_ESN_HIGH:
|
||||
retVal = MessageType.ID_ESNL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( channel > 0 )
|
||||
{
|
||||
int free = getFree();
|
||||
|
||||
switch( free )
|
||||
{
|
||||
case sFREE_CALL:
|
||||
retVal = MessageType.CA_STRT;
|
||||
break;
|
||||
case sFREE_END_CALL:
|
||||
retVal = MessageType.CA_ENDD;
|
||||
break;
|
||||
case sFREE_REQUEST_ACCESS:
|
||||
retVal = MessageType.RQ_ACCE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
@Override
|
||||
public String getFromID()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getFromIDAlias()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuxiliaryMessage( LTRNetOSWMessage message )
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plottable getPlottable()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a listing of aliases contained in the message.
|
||||
*/
|
||||
public List<Alias> getAliases()
|
||||
{
|
||||
List<Alias> aliases = new ArrayList<Alias>();
|
||||
|
||||
Alias from = getFromIDAlias();
|
||||
|
||||
if( from != null )
|
||||
{
|
||||
aliases.add( from );
|
||||
}
|
||||
|
||||
Alias to = getToIDAlias();
|
||||
|
||||
if( to != null )
|
||||
{
|
||||
aliases.add( to );
|
||||
}
|
||||
|
||||
Alias esn = getESNAlias();
|
||||
|
||||
if( esn != null )
|
||||
{
|
||||
aliases.add( esn );
|
||||
}
|
||||
|
||||
return aliases;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.ltrnet;
|
||||
|
||||
import io.github.dsheirer.alias.Alias;
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.edac.CRC;
|
||||
import io.github.dsheirer.edac.CRCLTR;
|
||||
import io.github.dsheirer.message.Message;
|
||||
import io.github.dsheirer.message.MessageDirection;
|
||||
import io.github.dsheirer.message.MessageType;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
public abstract class LTRNetMessage extends Message
|
||||
{
|
||||
protected static final String sUNKNOWN = "**UNKNOWN**";
|
||||
protected static final int INT_NULL_VALUE = -1;
|
||||
protected static final double sDOUBLE_NULL_VALUE = -1.0D;
|
||||
protected SimpleDateFormat mDatestampFormatter =
|
||||
new SimpleDateFormat( "yyyyMMdd HHmmss" );
|
||||
protected DecimalFormat mDecimalFormatter = new DecimalFormat("0.00000");
|
||||
|
||||
protected static final int[] sSYNC = { 8,7,6,5,4,3,2,1,0 };
|
||||
protected static final int[] sAREA = { 9 };
|
||||
protected static final int[] sCHANNEL = { 14,13,12,11,10 };
|
||||
protected static final int[] sHOME_REPEATER = { 19,18,17,16,15 };
|
||||
protected static final int[] sGROUP = { 27,26,25,24,23,22,21,20 };
|
||||
protected static final int[] sFREE = { 32,31,30,29,28 };
|
||||
protected static final int[] sCRC = { 39,38,37,36,35,34,33 };
|
||||
protected static final int[] sSIXTEEN_BITS = { 32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17 };
|
||||
protected static final int[] sMANUFACTURER_ID = { 23,22,21,20,19,18,17 };
|
||||
|
||||
protected BinaryMessage mMessage;
|
||||
protected MessageType mMessageType;
|
||||
protected CRC mCRC;
|
||||
protected AliasList mAliasList;
|
||||
|
||||
public LTRNetMessage( BinaryMessage message,
|
||||
MessageDirection direction,
|
||||
AliasList list )
|
||||
{
|
||||
mMessage = message;
|
||||
mCRC = CRCLTR.check( message, direction );
|
||||
mAliasList = list;
|
||||
}
|
||||
|
||||
public MessageType getMessageType()
|
||||
{
|
||||
return mMessageType;
|
||||
}
|
||||
|
||||
public abstract void setAuxiliaryMessage( LTRNetOSWMessage message );
|
||||
|
||||
public boolean isValid()
|
||||
{
|
||||
return mCRC != CRC.FAILED_CRC && mCRC != CRC.FAILED_PARITY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends spaces to the end of the stringbuilder to make it length long
|
||||
*/
|
||||
protected void pad( StringBuilder sb, int length )
|
||||
{
|
||||
while( sb.length() < length )
|
||||
{
|
||||
sb.append( " " );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBinaryMessage()
|
||||
{
|
||||
return mMessage.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value formatted in hex notation.
|
||||
*
|
||||
* @param value - integer value
|
||||
* @return - hex digits returned
|
||||
*/
|
||||
protected static String getHex( int value, int digits )
|
||||
{
|
||||
return String.format( "%0" + digits + "X", value );
|
||||
}
|
||||
|
||||
protected int getInt( int[] bits )
|
||||
{
|
||||
int retVal = 0;
|
||||
|
||||
for( int x = 0; x < bits.length; x++ )
|
||||
{
|
||||
if( mMessage.get( bits[ x ] ) )
|
||||
{
|
||||
retVal += 1<<x;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads an integer value with additional zeroes to make it decimalPlaces long
|
||||
*/
|
||||
public String format( int number, int decimalPlaces )
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int paddingRequired = decimalPlaces - ( String.valueOf( number ).length() );
|
||||
|
||||
for( int x = 0; x < paddingRequired; x++)
|
||||
{
|
||||
sb.append( "0" );
|
||||
}
|
||||
|
||||
sb.append( number );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String format( String val, int places )
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( val );
|
||||
|
||||
while( sb.length() < places )
|
||||
{
|
||||
sb.append( " " );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public CRC getCRC()
|
||||
{
|
||||
return mCRC;
|
||||
}
|
||||
|
||||
public int getArea()
|
||||
{
|
||||
return getInt( sAREA );
|
||||
}
|
||||
|
||||
public int getChannel()
|
||||
{
|
||||
return getInt( sCHANNEL );
|
||||
}
|
||||
|
||||
public int getHomeRepeater()
|
||||
{
|
||||
return getInt( sHOME_REPEATER );
|
||||
}
|
||||
|
||||
public int getGroup()
|
||||
{
|
||||
return getInt( sGROUP );
|
||||
}
|
||||
|
||||
public String getTalkgroupID()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( getArea() );
|
||||
sb.append( "-" );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( "-" );
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Alias getTalkgroupIDAlias()
|
||||
{
|
||||
return mAliasList.getTalkgroupAlias( getTalkgroupID() );
|
||||
}
|
||||
|
||||
public int getFree()
|
||||
{
|
||||
return getInt( sFREE );
|
||||
}
|
||||
|
||||
public int getCRCChecksum()
|
||||
{
|
||||
return getInt( sCRC );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol()
|
||||
{
|
||||
return DecoderType.LTR_NET.getDisplayString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventType()
|
||||
{
|
||||
if( mMessageType != null )
|
||||
{
|
||||
return mMessageType.getDisplayText();
|
||||
}
|
||||
else
|
||||
{
|
||||
return MessageType.UN_KNWN.getDisplayText();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToID()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getToIDAlias()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorStatus()
|
||||
{
|
||||
return mCRC.getDisplayText();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package io.github.dsheirer.module.decode.ltrnet;
|
||||
|
||||
import io.github.dsheirer.filter.Filter;
|
||||
import io.github.dsheirer.filter.FilterElement;
|
||||
import io.github.dsheirer.message.Message;
|
||||
import io.github.dsheirer.message.MessageType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class LTRNetMessageFilter extends Filter<Message>
|
||||
{
|
||||
private HashMap<MessageType, FilterElement<MessageType>> mElements =
|
||||
new HashMap<MessageType, FilterElement<MessageType>>();
|
||||
|
||||
public LTRNetMessageFilter()
|
||||
{
|
||||
super( "LTR-Net Message Filter" );
|
||||
|
||||
mElements.put( MessageType.CA_STRT,
|
||||
new FilterElement<MessageType>( MessageType.CA_STRT ) );
|
||||
mElements.put( MessageType.CA_ENDD,
|
||||
new FilterElement<MessageType>( MessageType.CA_ENDD ) );
|
||||
mElements.put( MessageType.SY_IDLE,
|
||||
new FilterElement<MessageType>( MessageType.SY_IDLE ) );
|
||||
mElements.put( MessageType.ID_UNIQ,
|
||||
new FilterElement<MessageType>( MessageType.ID_UNIQ ) );
|
||||
mElements.put( MessageType.ID_ESNH,
|
||||
new FilterElement<MessageType>( MessageType.ID_ESNH ) );
|
||||
mElements.put( MessageType.ID_ESNL,
|
||||
new FilterElement<MessageType>( MessageType.ID_ESNL ) );
|
||||
mElements.put( MessageType.RQ_ACCE,
|
||||
new FilterElement<MessageType>( MessageType.RQ_ACCE ) );
|
||||
mElements.put( MessageType.ID_SITE,
|
||||
new FilterElement<MessageType>( MessageType.ID_SITE ) );
|
||||
mElements.put( MessageType.FQ_RXHI,
|
||||
new FilterElement<MessageType>( MessageType.FQ_RXHI ) );
|
||||
mElements.put( MessageType.FQ_RXLO,
|
||||
new FilterElement<MessageType>( MessageType.FQ_RXLO ) );
|
||||
mElements.put( MessageType.FQ_TXHI,
|
||||
new FilterElement<MessageType>( MessageType.FQ_TXHI ) );
|
||||
mElements.put( MessageType.FQ_TXLO,
|
||||
new FilterElement<MessageType>( MessageType.FQ_TXLO ) );
|
||||
mElements.put( MessageType.ID_NBOR,
|
||||
new FilterElement<MessageType>( MessageType.ID_NBOR ) );
|
||||
mElements.put( MessageType.MA_CHNH,
|
||||
new FilterElement<MessageType>( MessageType.MA_CHNH ) );
|
||||
mElements.put( MessageType.MA_CHNL,
|
||||
new FilterElement<MessageType>( MessageType.MA_CHNL ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passes( Message message )
|
||||
{
|
||||
if( mEnabled && canProcess( message ) )
|
||||
{
|
||||
LTRNetMessage ltr = (LTRNetMessage)message;
|
||||
|
||||
if( mElements.containsKey( ltr.getMessageType() ) )
|
||||
{
|
||||
return mElements.get( ltr.getMessageType() ).isEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcess( Message message )
|
||||
{
|
||||
return message instanceof LTRNetMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FilterElement<?>> getFilterElements()
|
||||
{
|
||||
return new ArrayList<FilterElement<?>>( mElements.values() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.ltrnet;
|
||||
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.message.Message;
|
||||
import io.github.dsheirer.message.MessageDirection;
|
||||
import io.github.dsheirer.message.MessageType;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class LTRNetMessageProcessor implements Listener<BinaryMessage>
|
||||
{
|
||||
private Listener<Message> mMessageListener;
|
||||
|
||||
private HashMap<Integer,LTRNetOSWMessage> mReceiveHighAuxMessages =
|
||||
new HashMap<Integer,LTRNetOSWMessage>();
|
||||
private HashMap<Integer,LTRNetOSWMessage> mReceiveLowAuxMessages =
|
||||
new HashMap<Integer,LTRNetOSWMessage>();
|
||||
|
||||
private HashMap<Integer,LTRNetOSWMessage> mTransmitHighAuxMessages =
|
||||
new HashMap<Integer,LTRNetOSWMessage>();
|
||||
private HashMap<Integer,LTRNetOSWMessage> mTransmitLowAuxMessages =
|
||||
new HashMap<Integer,LTRNetOSWMessage>();
|
||||
|
||||
private LTRNetISWMessage mESNHighMessage;
|
||||
private LTRNetISWMessage mESNLowMessage;
|
||||
|
||||
private MessageDirection mDirection;
|
||||
private AliasList mAliasList;
|
||||
|
||||
public LTRNetMessageProcessor( MessageDirection direction, AliasList list )
|
||||
{
|
||||
mDirection = direction;
|
||||
mAliasList = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( BinaryMessage buffer )
|
||||
{
|
||||
if( mMessageListener != null )
|
||||
{
|
||||
LTRNetMessage message;
|
||||
|
||||
if( mDirection == MessageDirection.OSW )
|
||||
{
|
||||
message = new LTRNetOSWMessage( buffer, mAliasList );
|
||||
|
||||
if( message.isValid() )
|
||||
{
|
||||
if( message.getMessageType() == MessageType.FQ_TXHI )
|
||||
{
|
||||
mTransmitHighAuxMessages.put( message.getHomeRepeater(), (LTRNetOSWMessage)message );
|
||||
|
||||
message.setAuxiliaryMessage( mTransmitLowAuxMessages.get(message.getHomeRepeater() ) );
|
||||
}
|
||||
else if( message.getMessageType() == MessageType.FQ_TXLO )
|
||||
{
|
||||
mTransmitLowAuxMessages.put( message.getHomeRepeater(),
|
||||
(LTRNetOSWMessage)message );
|
||||
|
||||
message.setAuxiliaryMessage( mTransmitHighAuxMessages.get(
|
||||
message.getHomeRepeater() ) );
|
||||
}
|
||||
else if( message.getMessageType() == MessageType.FQ_RXHI )
|
||||
{
|
||||
mReceiveHighAuxMessages.put( message.getHomeRepeater(),
|
||||
(LTRNetOSWMessage)message );
|
||||
|
||||
message.setAuxiliaryMessage( mReceiveLowAuxMessages.get(
|
||||
message.getHomeRepeater() ) );
|
||||
}
|
||||
else if( message.getMessageType() == MessageType.FQ_RXLO )
|
||||
{
|
||||
mReceiveLowAuxMessages.put( message.getHomeRepeater(),
|
||||
(LTRNetOSWMessage)message );
|
||||
message.setAuxiliaryMessage( mReceiveHighAuxMessages.get(
|
||||
message.getHomeRepeater() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.flip( 0, 40 );
|
||||
|
||||
message = new LTRNetISWMessage( buffer, mAliasList );
|
||||
|
||||
if( message.isValid() )
|
||||
{
|
||||
/**
|
||||
* Catch ESN High messages to marry up with ESN Low messages. Purge
|
||||
* the ESN high message after 2 messages, so that it doesn't get
|
||||
* paired with the wrong esn low message
|
||||
*/
|
||||
if( message.getMessageType() == MessageType.ID_ESNH )
|
||||
{
|
||||
mESNHighMessage = (LTRNetISWMessage)message;
|
||||
|
||||
if( mESNLowMessage != null )
|
||||
{
|
||||
/* Check that the stored message is not older than
|
||||
* 5 seconds */
|
||||
if( System.currentTimeMillis() -
|
||||
mESNLowMessage.getTimeReceived() < 5000 )
|
||||
{
|
||||
((LTRNetISWMessage)message).setAuxiliaryMessage( mESNLowMessage );
|
||||
}
|
||||
else
|
||||
{
|
||||
mESNLowMessage = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( message.getMessageType() == MessageType.ID_ESNL )
|
||||
{
|
||||
mESNLowMessage = (LTRNetISWMessage)message;
|
||||
|
||||
if( mESNHighMessage != null )
|
||||
{
|
||||
/* Check that the stored message is not older than 5 seconds */
|
||||
if( System.currentTimeMillis() - mESNHighMessage.getTimeReceived() < 5000 )
|
||||
{
|
||||
((LTRNetISWMessage)message).setAuxiliaryMessage( mESNHighMessage );
|
||||
}
|
||||
else
|
||||
{
|
||||
mESNHighMessage = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mMessageListener.receive( message );
|
||||
}
|
||||
}
|
||||
|
||||
public void setMessageListener( Listener<Message> listener )
|
||||
{
|
||||
mMessageListener = listener;
|
||||
}
|
||||
|
||||
public void removeMessageListener()
|
||||
{
|
||||
mMessageListener = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,644 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.ltrnet;
|
||||
|
||||
import io.github.dsheirer.alias.Alias;
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.map.Plottable;
|
||||
import io.github.dsheirer.message.MessageDirection;
|
||||
import io.github.dsheirer.message.MessageType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class LTRNetOSWMessage extends LTRNetMessage
|
||||
{
|
||||
private static final int CHANNEL_FREQUENCY_MESSAGE_TYPE_BIT = 20;
|
||||
private static final int CHANNEL_MAP_MESSAGE_TYPE_BIT = 17;
|
||||
|
||||
private static final int CHIU_UNIQUE_ID = 17;
|
||||
private static final int CHIU_SITE_ID = 18;
|
||||
private static final int CHIU_TRANSMIT_FREQUENCY = 24;
|
||||
private static final int CHIU_RECEIVE_FREQUENCY = 25;
|
||||
private static final int CHIU_NEIGHBOR = 26;
|
||||
private static final int CHIU_MAP = 28;
|
||||
private static final int CHIU_CALL_END = 31;
|
||||
|
||||
private static final int HOME_DIRECTED_GROUP_CALL = 29;
|
||||
private static final int HOME_CHANNEL_IN_USE_MUTE_AUDIO = 30;
|
||||
|
||||
private static final int GROUP_DO_NOTHING = 253;
|
||||
private static final int GROUP_CWID = 254;
|
||||
private static final int GROUP_CHANNEL_IDLE = 255;
|
||||
|
||||
private static final int FREE_ALL_CHANNELS_BUSY = 0;
|
||||
private static final int FREE_LTR_GROUP_CALL = 30;
|
||||
private static final int FREE_LTRNET_GROUP_CALL = 31;
|
||||
|
||||
private LTRNetOSWMessage mAuxMessage;
|
||||
|
||||
public LTRNetOSWMessage( BinaryMessage message, AliasList list )
|
||||
{
|
||||
super( message, MessageDirection.OSW, list );
|
||||
mMessageType = getType();
|
||||
}
|
||||
|
||||
public void setAuxiliaryMessage( LTRNetOSWMessage message )
|
||||
{
|
||||
if( message != null )
|
||||
{
|
||||
mAuxMessage = message;
|
||||
}
|
||||
}
|
||||
|
||||
public String getRadioUniqueIDText()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int radioId = getRadioUniqueID();
|
||||
|
||||
if( radioId != INT_NULL_VALUE )
|
||||
{
|
||||
sb.append( " RADIO UNIQUE ID: " );
|
||||
sb.append( radioId );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append( mDatestampFormatter.format(
|
||||
new Date( System.currentTimeMillis() ) ) );
|
||||
sb.append( " LTRNet OSW [" );
|
||||
sb.append( mCRC.getAbbreviation() );
|
||||
sb.append( "] " );
|
||||
sb.append( getMessage() );
|
||||
pad( sb, 100 );
|
||||
sb.append( mMessage.toString() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
switch( mMessageType )
|
||||
{
|
||||
case SY_IDLE:
|
||||
sb.append( "IDLE AREA:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " LCN:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " HOME:" );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( " GRP:" );
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
sb.append( " FREE:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
break;
|
||||
case CA_STRT:
|
||||
sb.append( "CALL LCN:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " TG [ " );
|
||||
sb.append( getTalkgroupID() );
|
||||
sb.append( "/" );
|
||||
sb.append( getTalkgroupIDAlias() );
|
||||
sb.append( " ] FREE:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
break;
|
||||
case CA_ENDD:
|
||||
sb.append( "END* AREA:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " LCN:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " TG [" );
|
||||
sb.append( getTalkgroupID() );
|
||||
sb.append( "/" );
|
||||
sb.append( getTalkgroupIDAlias() );
|
||||
sb.append( "] FREE:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
break;
|
||||
case MA_CHNL:
|
||||
sb.append( "CHAN MAP LOW LCN [" );
|
||||
sb.append( getChannelMapAsString( getChannelMapLow() ) );
|
||||
sb.append( "]" );
|
||||
break;
|
||||
case MA_CHNH:
|
||||
sb.append( "CHAN MAP HIGH LCN [" );
|
||||
sb.append( getChannelMapAsString( getChannelMapHigh() ) );
|
||||
sb.append( "]" );
|
||||
break;
|
||||
case FQ_RXLO:
|
||||
sb.append( "CHAN RX LOW LCN:" );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( " = " );
|
||||
long rxFreqLo = getFrequency();
|
||||
if( rxFreqLo > 0 )
|
||||
{
|
||||
sb.append( mDecimalFormatter.format( (double)rxFreqLo / 1E6d ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "000.00000" );
|
||||
}
|
||||
sb.append( " MHz" );
|
||||
break;
|
||||
case FQ_RXHI:
|
||||
sb.append( "CHAN RX HIGH LCN:" );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( " = " );
|
||||
long rxfreqhi = getFrequency();
|
||||
if( rxfreqhi > 0 )
|
||||
{
|
||||
sb.append( mDecimalFormatter.format( (double)rxfreqhi / 1E6d ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "000.00000" );
|
||||
}
|
||||
sb.append( " MHz" );
|
||||
break;
|
||||
case FQ_TXHI:
|
||||
sb.append( "CHAN TX LOW LCN:" );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( " = " );
|
||||
long txfreq = getFrequency();
|
||||
if( txfreq > 0 )
|
||||
{
|
||||
sb.append( mDecimalFormatter.format( (double)txfreq / 1E6d ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "000.00000" );
|
||||
}
|
||||
sb.append( " MHz" );
|
||||
break;
|
||||
case FQ_TXLO:
|
||||
sb.append( "CHAN TX HIGH LCN:" );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( " = " );
|
||||
long txFreqLo = getFrequency();
|
||||
if( txFreqLo > 0 )
|
||||
{
|
||||
sb.append( mDecimalFormatter.format( (double)txFreqLo / 1E6d ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "000.00000" );
|
||||
}
|
||||
sb.append( " MHz" );
|
||||
break;
|
||||
case ID_SITE:
|
||||
String siteId = getSiteID();
|
||||
if( siteId != null )
|
||||
{
|
||||
sb.append( "SITE ID: " );
|
||||
sb.append( siteId );
|
||||
sb.append( " " );
|
||||
sb.append( getSiteIDAlias() );
|
||||
}
|
||||
break;
|
||||
case ID_NBOR:
|
||||
int neighborRank = getNeighborRank();
|
||||
String neighborId = getNeighborID();
|
||||
|
||||
if( neighborRank != INT_NULL_VALUE &&
|
||||
neighborId != null )
|
||||
{
|
||||
sb.append( "NEIGHBOR SITE " );
|
||||
sb.append( neighborRank );
|
||||
sb.append( ": " );
|
||||
sb.append( neighborId );
|
||||
sb.append( " " );
|
||||
sb.append( getNeighborIDAlias() );
|
||||
}
|
||||
break;
|
||||
case ID_UNIQ:
|
||||
sb.append( "REGISTER RADIO UNIQUE ID:" );
|
||||
sb.append( getRadioUniqueID() );
|
||||
break;
|
||||
default:
|
||||
sb.append( "UNKNOWN " );
|
||||
sb.append( getArea() );
|
||||
sb.append( " " + format( getChannel(), 2 ) );
|
||||
sb.append( " " + format( getHomeRepeater(), 2 ) );
|
||||
sb.append( " " + format( getGroup(), 3 ) );
|
||||
sb.append( " " + format( getFree(), 2 ) );
|
||||
sb.append( " A:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " C:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " H:" );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( " G:" );
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
sb.append( " F:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getTalkgroupID()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( getArea() );
|
||||
sb.append( "-" );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( "-" );
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Alias getTalkgroupIDAlias()
|
||||
{
|
||||
if( mAliasList != null )
|
||||
{
|
||||
return mAliasList.getTalkgroupAlias( getTalkgroupID() );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ArrayList<Integer> getChannelMapLow()
|
||||
{
|
||||
ArrayList<Integer> retVal = new ArrayList<Integer>();
|
||||
|
||||
if( mMessageType == MessageType.MA_CHNL )
|
||||
{
|
||||
for( int x = 27; x >= 18; x-- )
|
||||
{
|
||||
if( mMessage.get( x ) )
|
||||
{
|
||||
retVal.add( 28 - x );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public ArrayList<Integer> getChannelMapHigh()
|
||||
{
|
||||
ArrayList<Integer> retVal = new ArrayList<Integer>();
|
||||
|
||||
if( mMessageType == MessageType.MA_CHNH )
|
||||
{
|
||||
for( int x = 27; x >= 18; x-- )
|
||||
{
|
||||
if( mMessage.get( x ) )
|
||||
{
|
||||
retVal.add( 38 - x );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public String getChannelMapAsString( ArrayList<Integer> channels )
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for( Integer channel: channels )
|
||||
{
|
||||
sb.append( channel );
|
||||
sb.append( " " );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public int getRadioUniqueID()
|
||||
{
|
||||
int retVal = INT_NULL_VALUE;
|
||||
|
||||
if( mMessageType == MessageType.ID_UNIQ )
|
||||
{
|
||||
retVal = mMessage.getInt( 17, 32 );
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public Alias getRadioUniqueIDAlias()
|
||||
{
|
||||
if( mAliasList != null )
|
||||
{
|
||||
return mAliasList.getUniqueID( getRadioUniqueID() );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getSiteID()
|
||||
{
|
||||
if( mMessageType == MessageType.ID_SITE )
|
||||
{
|
||||
return String.valueOf( mMessage.getInt( 23, 32 ) );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Alias getSiteIDAlias()
|
||||
{
|
||||
if( mAliasList != null )
|
||||
{
|
||||
return mAliasList.getSiteID( getSiteID() );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getNeighborID()
|
||||
{
|
||||
if( mMessageType == MessageType.ID_NBOR )
|
||||
{
|
||||
int id = mMessage.getInt( 23, 32 );
|
||||
|
||||
if( id > 0 )
|
||||
{
|
||||
return String.valueOf( id );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Alias getNeighborIDAlias()
|
||||
{
|
||||
if( mAliasList != null )
|
||||
{
|
||||
return mAliasList.getSiteID( getNeighborID() );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getNeighborRank()
|
||||
{
|
||||
int retVal = INT_NULL_VALUE;
|
||||
|
||||
if( mMessageType == MessageType.ID_NBOR )
|
||||
{
|
||||
retVal = mMessage.getInt( 15, 18 ) + 1;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public long getFrequency()
|
||||
{
|
||||
long retVal = 0;
|
||||
|
||||
if( mAuxMessage != null )
|
||||
{
|
||||
int high;
|
||||
int low;
|
||||
|
||||
MessageType type = getMessageType();
|
||||
|
||||
if( type == MessageType.FQ_RXHI || type == MessageType.FQ_TXHI )
|
||||
{
|
||||
high = getHighChannelUnits();
|
||||
low = mAuxMessage.getLowChannelUnits();
|
||||
}
|
||||
else
|
||||
{
|
||||
high = mAuxMessage.getHighChannelUnits();
|
||||
low = getLowChannelUnits();
|
||||
}
|
||||
|
||||
if( high != INT_NULL_VALUE && low != INT_NULL_VALUE )
|
||||
{
|
||||
retVal = ( high + low ) * 1250 + 150000000;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the high order (15 - 12) frequency bits which are
|
||||
* the lower 4 bits of the Free field, left shifted by 12, representing the
|
||||
* frequency value in units of .00125 MHz
|
||||
*/
|
||||
public int getHighChannelUnits()
|
||||
{
|
||||
int retVal = INT_NULL_VALUE;
|
||||
|
||||
if( mAuxMessage != null &&
|
||||
( mMessageType == MessageType.FQ_RXHI ||
|
||||
mMessageType == MessageType.FQ_TXHI ) )
|
||||
{
|
||||
retVal = mMessage.getInt( 29, 32 );
|
||||
|
||||
retVal = Integer.rotateLeft( retVal, 12 );
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the low order (11 - 0) frequency bits which are
|
||||
* contained in the Group and Free fields representing the frequency value
|
||||
* units of .00125 MHz
|
||||
*/
|
||||
public int getLowChannelUnits()
|
||||
{
|
||||
int retVal = INT_NULL_VALUE;
|
||||
|
||||
if( mMessageType == MessageType.FQ_RXLO ||
|
||||
mMessageType == MessageType.FQ_TXLO )
|
||||
{
|
||||
retVal = mMessage.getInt( 21, 32 );
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public MessageType getType()
|
||||
{
|
||||
MessageType retVal = MessageType.UN_KNWN;
|
||||
|
||||
int channel = getChannel();
|
||||
|
||||
int home = getHomeRepeater();
|
||||
|
||||
//LTR-Net messages
|
||||
if( home != 31 && ( channel > 20 || home > 20 ) )
|
||||
{
|
||||
switch( channel )
|
||||
{
|
||||
case CHIU_UNIQUE_ID:
|
||||
retVal = MessageType.ID_UNIQ;
|
||||
break;
|
||||
case CHIU_SITE_ID:
|
||||
retVal = MessageType.ID_SITE;
|
||||
break;
|
||||
case CHIU_TRANSMIT_FREQUENCY:
|
||||
if( getHomeRepeater() == 24 )
|
||||
{
|
||||
retVal = MessageType.ID_UNIQ;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( mMessage.get( CHANNEL_FREQUENCY_MESSAGE_TYPE_BIT ) )
|
||||
{
|
||||
retVal = MessageType.FQ_TXHI;
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = MessageType.FQ_TXLO;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHIU_RECEIVE_FREQUENCY:
|
||||
if( mMessage.get( CHANNEL_FREQUENCY_MESSAGE_TYPE_BIT ) )
|
||||
{
|
||||
retVal = MessageType.FQ_RXHI;
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = MessageType.FQ_RXLO;
|
||||
}
|
||||
break;
|
||||
case CHIU_NEIGHBOR:
|
||||
retVal = MessageType.ID_NBOR;
|
||||
break;
|
||||
case CHIU_MAP:
|
||||
if( mMessage.get( CHANNEL_MAP_MESSAGE_TYPE_BIT ) )
|
||||
{
|
||||
retVal = MessageType.MA_CHNH;
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = MessageType.MA_CHNL;
|
||||
}
|
||||
break;
|
||||
case CHIU_CALL_END:
|
||||
retVal = MessageType.CA_ENDD;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int group = getGroup();
|
||||
|
||||
if( group == GROUP_CHANNEL_IDLE )
|
||||
{
|
||||
retVal = MessageType.SY_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = MessageType.CA_STRT;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFromID()
|
||||
{
|
||||
if( mMessageType == MessageType.CA_STRT ||
|
||||
mMessageType == MessageType.CA_ENDD )
|
||||
{
|
||||
return getTalkgroupID();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getFromIDAlias()
|
||||
{
|
||||
if( mMessageType == MessageType.CA_STRT ||
|
||||
mMessageType == MessageType.CA_ENDD )
|
||||
{
|
||||
return getTalkgroupIDAlias();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plottable getPlottable()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a listing of aliases contained in the message.
|
||||
*/
|
||||
public List<Alias> getAliases()
|
||||
{
|
||||
List<Alias> aliases = new ArrayList<Alias>();
|
||||
|
||||
Alias from = getFromIDAlias();
|
||||
|
||||
if( from != null )
|
||||
{
|
||||
aliases.add( from );
|
||||
}
|
||||
|
||||
Alias to = getToIDAlias();
|
||||
|
||||
if( to != null )
|
||||
{
|
||||
aliases.add( to );
|
||||
}
|
||||
|
||||
Alias neighbor = getNeighborIDAlias();
|
||||
|
||||
if( neighbor != null )
|
||||
{
|
||||
aliases.add( neighbor );
|
||||
}
|
||||
|
||||
Alias uid = getRadioUniqueIDAlias();
|
||||
|
||||
if( uid != null )
|
||||
{
|
||||
aliases.add( uid );
|
||||
}
|
||||
|
||||
Alias site = getSiteIDAlias();
|
||||
|
||||
if( site != null )
|
||||
{
|
||||
aliases.add( site );
|
||||
}
|
||||
|
||||
return aliases;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user