mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-13 17:17:29 -05:00
Initial code check in continued
This commit is contained in:
233
src/decode/passport/PassportActivitySummary.java
Normal file
233
src/decode/passport/PassportActivitySummary.java
Normal file
@@ -0,0 +1,233 @@
|
||||
/*******************************************************************************
|
||||
* 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 decode.passport;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import message.Message;
|
||||
import sample.Listener;
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import controller.activity.ActivitySummaryProvider;
|
||||
|
||||
public class PassportActivitySummary implements ActivitySummaryProvider,
|
||||
Listener<Message>
|
||||
{
|
||||
private static final int sINT_NULL_VALUE = -1;
|
||||
private DecimalFormat mDecimalFormatter = new DecimalFormat("0.00000");
|
||||
|
||||
private AliasList mAliasList;
|
||||
private HashSet<String> mTalkgroupsFirstHeard = new HashSet<String>();
|
||||
private TreeSet<String> mTalkgroups = new TreeSet<String>();
|
||||
private TreeSet<String> mMobileIDs = new TreeSet<String>();
|
||||
private HashMap<Integer,String> mSiteLCNs = new HashMap<Integer,String>();
|
||||
private HashMap<Integer,String> mNeighborLCNs = new HashMap<Integer,String>();
|
||||
|
||||
/**
|
||||
* Compiles a summary of active talkgroups, unique radio ids encountered
|
||||
* in the decoded messages. Talkgroups have to be heard a minimum of twice
|
||||
* to be considered valid ... in order to weed out the invalid ones.
|
||||
*
|
||||
* Returns a textual summary of the activity
|
||||
*/
|
||||
public PassportActivitySummary( AliasList list )
|
||||
{
|
||||
mAliasList = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( Message message )
|
||||
{
|
||||
if( message instanceof PassportMessage )
|
||||
{
|
||||
PassportMessage passport = ((PassportMessage)message);
|
||||
|
||||
if( passport.isValid() )
|
||||
{
|
||||
switch( passport.getMessageType() )
|
||||
{
|
||||
case CA_STRT:
|
||||
mSiteLCNs.put( passport.getLCN(),
|
||||
passport.getLCNFrequencyFormatted() );
|
||||
case CA_ENDD:
|
||||
String talkgroup =
|
||||
String.valueOf( passport.getTalkgroupID() );
|
||||
|
||||
if( mTalkgroupsFirstHeard.contains( talkgroup ) )
|
||||
{
|
||||
mTalkgroups.add( talkgroup );
|
||||
}
|
||||
else
|
||||
{
|
||||
mTalkgroupsFirstHeard.add( talkgroup );
|
||||
}
|
||||
break;
|
||||
case ID_RDIO:
|
||||
String min = passport.getMobileID();
|
||||
|
||||
if( min != null )
|
||||
{
|
||||
mMobileIDs.add( min );
|
||||
}
|
||||
break;
|
||||
case SY_IDLE:
|
||||
if( passport.getFree() != 0 )
|
||||
{
|
||||
mNeighborLCNs.put( passport.getFree(),
|
||||
passport.getFreeFrequencyFormatted() );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSummary()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "Activity Summary\n" );
|
||||
sb.append( "Decoder:\tPassport\n\n" );
|
||||
sb.append( "Site Channels\n" );
|
||||
|
||||
if( mSiteLCNs.isEmpty() )
|
||||
{
|
||||
sb.append( " None\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrayList<Integer> channels = new ArrayList( mSiteLCNs.keySet() );
|
||||
Collections.sort( channels );
|
||||
|
||||
for( Integer channel: channels )
|
||||
{
|
||||
sb.append( " " + channel );
|
||||
sb.append( "\t" + mSiteLCNs.get( channel ) );
|
||||
sb.append( "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
sb.append( "\nNeighbor Channels\n" );
|
||||
|
||||
if( mNeighborLCNs.isEmpty() )
|
||||
{
|
||||
sb.append( " None\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrayList<Integer> channels = new ArrayList( mNeighborLCNs.keySet() );
|
||||
Collections.sort( channels );
|
||||
|
||||
for( Integer channel: channels )
|
||||
{
|
||||
sb.append( " " + channel );
|
||||
sb.append( "\t" + mNeighborLCNs.get( channel ) );
|
||||
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( " " );
|
||||
|
||||
Alias alias = mAliasList.getTalkgroupAlias( tgid );
|
||||
|
||||
if( alias != null )
|
||||
{
|
||||
sb.append( alias.getName() );
|
||||
}
|
||||
|
||||
sb.append( "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
sb.append( "\nMobile ID Numbers\n" );
|
||||
|
||||
if( mMobileIDs.isEmpty() )
|
||||
{
|
||||
sb.append( " None\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
Iterator<String> it = mMobileIDs.iterator();
|
||||
|
||||
while( it.hasNext() )
|
||||
{
|
||||
String min = it.next();
|
||||
|
||||
sb.append( " " );
|
||||
sb.append( min );
|
||||
sb.append( " " );
|
||||
|
||||
Alias alias = mAliasList.getMobileIDNumberAlias( min );
|
||||
|
||||
if( alias != null )
|
||||
{
|
||||
sb.append( alias.getName() );
|
||||
}
|
||||
|
||||
sb.append( "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String formatTalkgroup( String talkgroup )
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if( talkgroup.length() == 6 )
|
||||
{
|
||||
sb.append( talkgroup.substring( 0, 1 ) );
|
||||
sb.append( "-" );
|
||||
sb.append( talkgroup.substring( 1, 3 ) );
|
||||
sb.append( "-" );
|
||||
sb.append( talkgroup.substring( 3, 6 ) );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return talkgroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
71
src/decode/passport/PassportBand.java
Normal file
71
src/decode/passport/PassportBand.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*******************************************************************************
|
||||
* 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 decode.passport;
|
||||
|
||||
public enum PassportBand
|
||||
{
|
||||
BAND_800( "800", 800000000 ),
|
||||
BAND_900( "900", 900000000 ),
|
||||
BAND_400( "400", 400000000 ),
|
||||
BAND_420( "420", 420000000 ),
|
||||
BAND_440( "440", 440000000 ),
|
||||
BAND_450( "450", 450000000 ),
|
||||
BAND_460( "460", 460000000 ),
|
||||
BAND_470( "470", 470000000 ),
|
||||
BAND_480( "480", 480000000 ),
|
||||
BAND_490( "490", 490000000 ),
|
||||
BAND_CANADA( "CAN", 0 ),
|
||||
BAND_NTIA( "NTIA", 0 ),
|
||||
BAND_RESERVED12( "RESVD", 0 ),
|
||||
BAND_216( "216", 216000000 ),
|
||||
BAND_RESERVED14( "RESVD", 0 ),
|
||||
BAND_700( "700", 700000000 ),
|
||||
BAND_VHF( "VHF", 0 ),
|
||||
BAND_UNKNOWN( "UNK", 0 );
|
||||
|
||||
private String mDescription;
|
||||
private int mBase;
|
||||
|
||||
private PassportBand( String description, int base )
|
||||
{
|
||||
mDescription = description;
|
||||
mBase = base;
|
||||
}
|
||||
|
||||
public static PassportBand lookup( int band )
|
||||
{
|
||||
if( band >= 0 && band < 16 )
|
||||
{
|
||||
return PassportBand.values()[ band ];
|
||||
}
|
||||
else
|
||||
{
|
||||
return PassportBand.BAND_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
public String getDescription()
|
||||
{
|
||||
return mDescription;
|
||||
}
|
||||
|
||||
public int getBase()
|
||||
{
|
||||
return mBase;
|
||||
}
|
||||
}
|
||||
164
src/decode/passport/PassportCallEvent.java
Normal file
164
src/decode/passport/PassportCallEvent.java
Normal file
@@ -0,0 +1,164 @@
|
||||
/*******************************************************************************
|
||||
* 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 decode.passport;
|
||||
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import controller.activity.CallEvent;
|
||||
import decode.DecoderType;
|
||||
|
||||
public class PassportCallEvent extends CallEvent
|
||||
{
|
||||
private int mChannel;
|
||||
private int mFrequency;
|
||||
|
||||
public PassportCallEvent( CallEventType callEventType,
|
||||
AliasList aliasList,
|
||||
String fromID,
|
||||
String toID,
|
||||
int channel,
|
||||
int frequency,
|
||||
String details )
|
||||
{
|
||||
super( DecoderType.PASSPORT, callEventType,
|
||||
aliasList, fromID, toID, details );
|
||||
|
||||
mChannel = channel;
|
||||
mFrequency = frequency;
|
||||
}
|
||||
|
||||
private Alias getAlias( String talkgroup )
|
||||
{
|
||||
if( hasAliasList() )
|
||||
{
|
||||
return getAliasList().getTalkgroupAlias( talkgroup );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Alias getMobileIDAlias( String mobileID )
|
||||
{
|
||||
if( hasAliasList() )
|
||||
{
|
||||
return getAliasList().getMobileIDNumberAlias( mobileID );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getFromIDAlias()
|
||||
{
|
||||
return getMobileIDAlias( getFromID() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getToIDAlias()
|
||||
{
|
||||
return getAlias( getToID() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChannel()
|
||||
{
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFrequency()
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
public static class Builder
|
||||
{
|
||||
/* Required parameters */
|
||||
private CallEventType mCallEventType;
|
||||
|
||||
/* Optional parameters */
|
||||
private AliasList mAliasList;
|
||||
private String mFromID;
|
||||
private String mToID;
|
||||
private String mDetails;
|
||||
private int mChannel;
|
||||
private int mFrequency;
|
||||
|
||||
public Builder( CallEventType callEventType )
|
||||
{
|
||||
mCallEventType = callEventType;
|
||||
}
|
||||
|
||||
public Builder aliasList( AliasList aliasList )
|
||||
{
|
||||
mAliasList = aliasList;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder from( String val )
|
||||
{
|
||||
mFromID = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder channel( int channel )
|
||||
{
|
||||
mChannel = channel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder details( String details )
|
||||
{
|
||||
mDetails = details;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder frequency( int frequency )
|
||||
{
|
||||
mFrequency = frequency;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder to( String toID )
|
||||
{
|
||||
mToID = toID;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PassportCallEvent build()
|
||||
{
|
||||
return new PassportCallEvent( this );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for the builder
|
||||
*/
|
||||
private PassportCallEvent( Builder builder )
|
||||
{
|
||||
this( builder.mCallEventType,
|
||||
builder.mAliasList,
|
||||
builder.mFromID,
|
||||
builder.mToID,
|
||||
builder.mChannel,
|
||||
builder.mFrequency,
|
||||
builder.mDetails );
|
||||
}
|
||||
|
||||
}
|
||||
236
src/decode/passport/PassportChannelState.java
Normal file
236
src/decode/passport/PassportChannelState.java
Normal file
@@ -0,0 +1,236 @@
|
||||
/*******************************************************************************
|
||||
* 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 decode.passport;
|
||||
|
||||
import message.Message;
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import audio.AudioType;
|
||||
import audio.SquelchListener;
|
||||
import controller.activity.CallEvent.CallEventType;
|
||||
import controller.channel.ProcessingChain;
|
||||
import controller.state.AuxChannelState;
|
||||
import controller.state.ChannelState;
|
||||
|
||||
public class PassportChannelState extends ChannelState
|
||||
{
|
||||
private String mTalkgroup;
|
||||
private Alias mTalkgroupAlias;
|
||||
private String mMobileID;
|
||||
private Alias mMobileIDAlias;
|
||||
private int mChannelNumber;
|
||||
private int mFrequency;
|
||||
private PassportCallEvent mCurrentCallEvent;
|
||||
private PassportActivitySummary mActivitySummary;
|
||||
|
||||
public PassportChannelState( ProcessingChain channel, AliasList aliasList )
|
||||
{
|
||||
super( channel, aliasList );
|
||||
|
||||
mActivitySummary = new PassportActivitySummary( aliasList );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivitySummary()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( mActivitySummary.getSummary() );
|
||||
|
||||
for( AuxChannelState state: mAuxChannelStates )
|
||||
{
|
||||
sb.append( state.getActivitySummary() );
|
||||
sb.append( "\n\n" );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings( "incomplete-switch" )
|
||||
public void receive( Message message )
|
||||
{
|
||||
super.receive( message );
|
||||
|
||||
if( message instanceof PassportMessage )
|
||||
{
|
||||
mActivitySummary.receive( message );
|
||||
|
||||
PassportMessage passport = (PassportMessage)message;
|
||||
|
||||
if( passport.isValid() )
|
||||
{
|
||||
switch( passport.getMessageType() )
|
||||
{
|
||||
case CA_STRT:
|
||||
setTalkgroup( String.valueOf( passport.getTalkgroupID() ) );
|
||||
setTalkgroupAlias( passport.getTalkgroupIDAlias() );
|
||||
|
||||
if( mTalkgroupAlias != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
if( mTalkgroupAlias.hasAudioType() )
|
||||
{
|
||||
mAudioTypeListener.setAudioType(
|
||||
mTalkgroupAlias.getAudioType() );
|
||||
}
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
mChannelNumber = passport.getLCN();
|
||||
mFrequency = passport.getLCNFrequency();
|
||||
|
||||
if( getState() != State.CALL )
|
||||
{
|
||||
mCurrentCallEvent = new PassportCallEvent
|
||||
.Builder( CallEventType.CALL_START )
|
||||
.aliasList( mAliasList )
|
||||
.channel( mChannelNumber )
|
||||
.frequency( mFrequency )
|
||||
.to( String.valueOf( passport.getTalkgroupID() ) )
|
||||
.build();
|
||||
|
||||
mCallEventModel.add( mCurrentCallEvent );
|
||||
}
|
||||
|
||||
setState( State.CALL );
|
||||
break;
|
||||
case DA_STRT:
|
||||
setTalkgroup( String.valueOf( passport.getTalkgroupID() ) );
|
||||
setTalkgroupAlias( passport.getTalkgroupIDAlias() );
|
||||
setState( State.DATA );
|
||||
break;
|
||||
case CA_ENDD:
|
||||
setTalkgroup( String.valueOf( passport.getTalkgroupID() ) );
|
||||
setTalkgroupAlias( passport.getTalkgroupIDAlias() );
|
||||
fade( CallEventType.CALL_END );
|
||||
break;
|
||||
case ID_RDIO:
|
||||
setMobileID( passport.getMobileID() );
|
||||
setMobileIDAlias( passport.getMobileIDAlias() );
|
||||
|
||||
if( mCurrentCallEvent != null )
|
||||
{
|
||||
mCurrentCallEvent.setFromID( mMobileID );
|
||||
}
|
||||
setState( State.CALL );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept the fade event so that we can generate a call end event
|
||||
*/
|
||||
@Override
|
||||
public void fade( final CallEventType type )
|
||||
{
|
||||
/*
|
||||
* We can receive multiple call tear-down messages -- only post a call
|
||||
* end event for the one that can change the state to fade
|
||||
*/
|
||||
if( getState().canChangeTo( State.FADE ) )
|
||||
{
|
||||
mCallEventModel.add(
|
||||
new PassportCallEvent.Builder( type )
|
||||
.aliasList( getAliasList() )
|
||||
.channel( mChannelNumber )
|
||||
.frequency( mProcessingChain.getChannel()
|
||||
.getTunerChannel().getFrequency() )
|
||||
.to( mTalkgroup )
|
||||
.build() );
|
||||
}
|
||||
|
||||
super.fade( type );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Make the ConventionalChannelState always unsquelched
|
||||
*/
|
||||
public void addListener( SquelchListener listener )
|
||||
{
|
||||
super.addListener( listener );
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
mAudioTypeListener.setAudioType( AudioType.NORMAL );
|
||||
|
||||
mCurrentCallEvent = null;
|
||||
|
||||
setTalkgroup( null );
|
||||
setTalkgroupAlias( null );
|
||||
|
||||
setMobileID( null );
|
||||
setMobileIDAlias( null );
|
||||
|
||||
super.reset();
|
||||
}
|
||||
|
||||
public String getTalkgroup()
|
||||
{
|
||||
return mTalkgroup;
|
||||
}
|
||||
|
||||
public void setTalkgroup( String talkgroup )
|
||||
{
|
||||
mTalkgroup = talkgroup;
|
||||
broadcastChange( ChangedAttribute.TO_TALKGROUP );
|
||||
}
|
||||
|
||||
public Alias getTalkgroupAlias()
|
||||
{
|
||||
return mTalkgroupAlias;
|
||||
}
|
||||
|
||||
public void setTalkgroupAlias( Alias alias )
|
||||
{
|
||||
mTalkgroupAlias = alias;
|
||||
broadcastChange( ChangedAttribute.TO_TALKGROUP_ALIAS );
|
||||
}
|
||||
|
||||
public String getMobileID()
|
||||
{
|
||||
return mMobileID;
|
||||
}
|
||||
|
||||
public void setMobileID( String id )
|
||||
{
|
||||
mMobileID = id;
|
||||
broadcastChange( ChangedAttribute.FROM_TALKGROUP );
|
||||
}
|
||||
|
||||
public Alias getMobileIDAlias()
|
||||
{
|
||||
return mMobileIDAlias;
|
||||
}
|
||||
|
||||
public void setMobileIDAlias( Alias alias )
|
||||
{
|
||||
mMobileIDAlias = alias;
|
||||
broadcastChange( ChangedAttribute.FROM_TALKGROUP_ALIAS );
|
||||
}
|
||||
}
|
||||
108
src/decode/passport/PassportDecoder.java
Normal file
108
src/decode/passport/PassportDecoder.java
Normal file
@@ -0,0 +1,108 @@
|
||||
/*******************************************************************************
|
||||
* 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 decode.passport;
|
||||
|
||||
import source.Source.SampleType;
|
||||
import alias.AliasList;
|
||||
import bits.MessageFramer;
|
||||
import bits.SyncPattern;
|
||||
import decode.Decoder;
|
||||
import decode.DecoderType;
|
||||
import decode.ltrstandard.LTRFSKDemodulator;
|
||||
import dsp.filter.DCRemovalFilter2;
|
||||
import dsp.nbfm.FilteringNBFMDemodulator;
|
||||
|
||||
public class PassportDecoder extends Decoder
|
||||
{
|
||||
/**
|
||||
* This value determines how quickly the DC remove filter responds to
|
||||
* changes in frequency.
|
||||
*/
|
||||
private static final double sDC_REMOVAL_RATIO = 0.000003;
|
||||
|
||||
public static final int sPASSPORT_MESSAGE_LENGTH = 68;
|
||||
public static final int sPASSPORT_SYNC_LENGTH = 9;
|
||||
private FilteringNBFMDemodulator mNBFMDemodulator;
|
||||
private DCRemovalFilter2 mDCRemovalFilter;
|
||||
private LTRFSKDemodulator mPassportFSKDemodulator;
|
||||
private MessageFramer mPassportMessageFramer;
|
||||
private PassportMessageProcessor mPassportMessageProcessor;
|
||||
|
||||
public PassportDecoder( SampleType sampleType, AliasList aliasList )
|
||||
{
|
||||
super( sampleType );
|
||||
|
||||
/**
|
||||
* Only setup a demod chain if we're receiving complex samples. If
|
||||
* we're receiving demodulated samples, they'll be handled the same
|
||||
* was as we handle the output of the demodulator.
|
||||
*/
|
||||
if( mSourceSampleType == SampleType.COMPLEX )
|
||||
{
|
||||
/**
|
||||
* The Decoder super class is both a Complex listener and a Short
|
||||
* listener. So, we add the demod to listen to the incoming
|
||||
* quadrature samples, and we wire the output of the demod right
|
||||
* back to this class, so we can receive the demodulated output
|
||||
* to process
|
||||
*/
|
||||
mNBFMDemodulator = new FilteringNBFMDemodulator();
|
||||
this.addComplexListener( mNBFMDemodulator );
|
||||
|
||||
/**
|
||||
* Remove the DC component that is present when we're mistuned
|
||||
*/
|
||||
mDCRemovalFilter = new DCRemovalFilter2( sDC_REMOVAL_RATIO );
|
||||
mNBFMDemodulator.addListener( mDCRemovalFilter );
|
||||
mDCRemovalFilter.setListener( this.getFloatReceiver() );
|
||||
}
|
||||
|
||||
mPassportFSKDemodulator =
|
||||
new LTRFSKDemodulator();
|
||||
|
||||
/**
|
||||
* The DC removal filter will impact performance of the LTRFSKDemod,
|
||||
* so we get the samples straight from the NBFM demod
|
||||
*/
|
||||
if( mSourceSampleType == SampleType.COMPLEX )
|
||||
{
|
||||
mNBFMDemodulator.addListener( mPassportFSKDemodulator );
|
||||
}
|
||||
else
|
||||
{
|
||||
addFloatListener( mPassportFSKDemodulator );
|
||||
}
|
||||
|
||||
|
||||
mPassportMessageFramer =
|
||||
new MessageFramer( SyncPattern.PASSPORT.getPattern(),
|
||||
sPASSPORT_MESSAGE_LENGTH );
|
||||
|
||||
mPassportFSKDemodulator.addListener( mPassportMessageFramer );
|
||||
|
||||
mPassportMessageProcessor = new PassportMessageProcessor( aliasList );
|
||||
mPassportMessageFramer.addMessageListener( mPassportMessageProcessor );
|
||||
mPassportMessageProcessor.addMessageListener( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecoderType getType()
|
||||
{
|
||||
return DecoderType.PASSPORT;
|
||||
}
|
||||
}
|
||||
31
src/decode/passport/PassportEditor.java
Normal file
31
src/decode/passport/PassportEditor.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*******************************************************************************
|
||||
* 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 decode.passport;
|
||||
|
||||
import decode.DecodeEditor;
|
||||
import decode.config.DecodeConfiguration;
|
||||
|
||||
public class PassportEditor extends DecodeEditor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public PassportEditor( DecodeConfiguration config )
|
||||
{
|
||||
super( config );
|
||||
}
|
||||
}
|
||||
634
src/decode/passport/PassportMessage.java
Normal file
634
src/decode/passport/PassportMessage.java
Normal file
@@ -0,0 +1,634 @@
|
||||
/*******************************************************************************
|
||||
* 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 decode.passport;
|
||||
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import map.Plottable;
|
||||
import message.Message;
|
||||
import message.MessageType;
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import bits.BitSetBuffer;
|
||||
import crc.CRC;
|
||||
import crc.CRCPassport;
|
||||
import decode.DecoderType;
|
||||
|
||||
public class PassportMessage extends Message
|
||||
{
|
||||
private static final String sUNKNOWN = "**UNKNOWN**";
|
||||
private static final int sINT_NULL_VALUE = -1;
|
||||
private static final double sDOUBLE_NULL_VALUE = -1.0D;
|
||||
private SimpleDateFormat mSDF = new SimpleDateFormat( "yyyyMMdd HHmmss" );
|
||||
private DecimalFormat mDecimalFormatter = new DecimalFormat("0.00000");
|
||||
|
||||
@SuppressWarnings( "unused" )
|
||||
private static final int[] sSYNC = { 8,7,6,5,4,3,2,1,0 };
|
||||
private static final int[] sDCC = { 10,9 }; //Digital Color Code
|
||||
private static final int[] sLCN = { 21,20,19,18,17,16,15,14,13,12,11 };
|
||||
private static final int[] sSITE = { 28,27,26,25,24,23,22 };
|
||||
private static final int[] sGROUP = { 44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29 };
|
||||
private static final int[] sRADIO_ID = { 44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22 };
|
||||
// private static final int[] sNEIGHBOR_OFFSET = { 32,31,30 };
|
||||
private static final int[] sNEIGHBOR_BAND = { 36,35,34,33 };
|
||||
private static final int[] sNEIGHBOR_REGISTRATION = { 29 };
|
||||
private static final int[] sSITE_OFFSET = { 40,39,38 };
|
||||
private static final int[] sSITE_BAND = { 44,43,42,41 };
|
||||
private static final int[] sSITE_REGISTRATION = { 37 };
|
||||
private static final int[] sTYPE = { 48,47,46,45 };
|
||||
private static final int[] sFREE = { 59,58,57,56,55,54,53,52,51,50,49 };
|
||||
private static final int[] sCHECKSUM = { 67,66,65,64,63,62,61,60 };
|
||||
private BitSetBuffer mMessage;
|
||||
private CRC mCRC;
|
||||
private AliasList mAliasList;
|
||||
private PassportMessage mIdleMessage;
|
||||
|
||||
public PassportMessage( BitSetBuffer message,
|
||||
PassportMessage idleMessage,
|
||||
AliasList list )
|
||||
{
|
||||
mMessage = CRCPassport.correct( message );
|
||||
mIdleMessage = idleMessage;
|
||||
mCRC = CRCPassport.check( mMessage );
|
||||
mAliasList = list;
|
||||
}
|
||||
|
||||
public PassportMessage( BitSetBuffer message, AliasList list )
|
||||
{
|
||||
this( message, null, list );
|
||||
}
|
||||
|
||||
public BitSetBuffer getBitSetBuffer()
|
||||
{
|
||||
return mMessage;
|
||||
}
|
||||
|
||||
public boolean isValid()
|
||||
{
|
||||
return mCRC != CRC.FAILED_CRC &&
|
||||
mCRC != CRC.FAILED_PARITY &&
|
||||
mCRC != CRC.UNKNOWN;
|
||||
}
|
||||
|
||||
public CRC getCRC()
|
||||
{
|
||||
return mCRC;
|
||||
}
|
||||
|
||||
public MessageType getMessageType()
|
||||
{
|
||||
MessageType retVal = MessageType.UN_KNWN;
|
||||
|
||||
int type = getMessageTypeNumber();
|
||||
int lcn = getLCN();
|
||||
|
||||
switch( type )
|
||||
{
|
||||
case 0: //Group Call
|
||||
retVal = MessageType.CA_STRT;
|
||||
break;
|
||||
case 1:
|
||||
if( getFree() == 2042 )
|
||||
{
|
||||
retVal = MessageType.ID_TGAS;
|
||||
}
|
||||
else if( lcn < 1792 )
|
||||
{
|
||||
retVal = MessageType.CA_STRT;
|
||||
}
|
||||
else if( lcn == 1792 || lcn == 1793 )
|
||||
{
|
||||
retVal = MessageType.SY_IDLE;
|
||||
}
|
||||
else if( lcn == 2047 )
|
||||
{
|
||||
retVal = MessageType.CA_ENDD;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
retVal = MessageType.CA_STRT;
|
||||
break;
|
||||
case 5:
|
||||
retVal = MessageType.CA_PAGE;
|
||||
break;
|
||||
case 6:
|
||||
retVal = MessageType.ID_RDIO;
|
||||
break;
|
||||
case 9:
|
||||
retVal = MessageType.DA_STRT;
|
||||
break;
|
||||
case 11:
|
||||
retVal = MessageType.RA_REGI;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
public int getDCC()
|
||||
{
|
||||
return getInt( sDCC );
|
||||
}
|
||||
|
||||
public int getSite()
|
||||
{
|
||||
return getInt( sSITE );
|
||||
}
|
||||
|
||||
public int getMessageTypeNumber()
|
||||
{
|
||||
return getInt( sTYPE );
|
||||
}
|
||||
|
||||
public int getTalkgroupID()
|
||||
{
|
||||
if( getMessageType() == MessageType.SY_IDLE )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return getInt( sGROUP );
|
||||
}
|
||||
}
|
||||
|
||||
public Alias getTalkgroupIDAlias()
|
||||
{
|
||||
int tg = getTalkgroupID();
|
||||
|
||||
return mAliasList.getTalkgroupAlias( String.valueOf( tg ) );
|
||||
}
|
||||
|
||||
public int getLCN()
|
||||
{
|
||||
return getInt( sLCN );
|
||||
}
|
||||
|
||||
public int getLCNFrequency()
|
||||
{
|
||||
return getSiteFrequency( getLCN() );
|
||||
}
|
||||
|
||||
public String getLCNFrequencyFormatted()
|
||||
{
|
||||
return mDecimalFormatter.format( (double)getLCNFrequency() / 1000000.0d );
|
||||
}
|
||||
|
||||
public PassportBand getSiteBand()
|
||||
{
|
||||
return PassportBand.lookup( getInt( sSITE_BAND ) );
|
||||
}
|
||||
|
||||
public PassportBand getNeighborBand()
|
||||
{
|
||||
return PassportBand.lookup( getInt( sNEIGHBOR_BAND ) );
|
||||
}
|
||||
|
||||
public int getFrequency( int base, int channel )
|
||||
{
|
||||
return ( base + ( channel * 12500 ) );
|
||||
}
|
||||
|
||||
public int getFree()
|
||||
{
|
||||
return getInt( sFREE );
|
||||
}
|
||||
|
||||
public int getFreeFrequency()
|
||||
{
|
||||
return getSiteFrequency( getFree() );
|
||||
}
|
||||
|
||||
public String getFreeFrequencyFormatted()
|
||||
{
|
||||
return mDecimalFormatter.format( (double)getFreeFrequency() / 1000000.0d );
|
||||
}
|
||||
|
||||
public int getNeighborFrequency()
|
||||
{
|
||||
int retVal = 0;
|
||||
|
||||
if( getMessageType() == MessageType.SY_IDLE )
|
||||
{
|
||||
PassportBand band = getNeighborBand();
|
||||
|
||||
retVal = getFrequency( band.getBase(), getFree() );
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the radio id in hex format, or null if not the correct message
|
||||
* type
|
||||
*
|
||||
* @return - radio id or null
|
||||
*/
|
||||
public String getMobileID()
|
||||
{
|
||||
if( getMessageType() == MessageType.ID_RDIO )
|
||||
{
|
||||
int radioId = getInt( sRADIO_ID );
|
||||
|
||||
return String.format("%06X", radioId & 0xFFFFFF );
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Alias getMobileIDAlias()
|
||||
{
|
||||
String min = getMobileID();
|
||||
|
||||
if( min != null )
|
||||
{
|
||||
return mAliasList.getMobileIDNumberAlias( min );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends spaces to the end of the stringbuilder to make it length long
|
||||
*/
|
||||
private 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
|
||||
*/
|
||||
private static String getHex( int value, int digits )
|
||||
{
|
||||
return String.format( "%0" + digits + "X", value );
|
||||
}
|
||||
|
||||
private 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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol()
|
||||
{
|
||||
return DecoderType.PASSPORT.getDisplayString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventType()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFromID()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getFromIDAlias()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToID()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getToIDAlias()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getSiteFrequency( int channel )
|
||||
{
|
||||
int freq = 0;
|
||||
|
||||
if( mIdleMessage != null && 0 < channel && channel < 1792 )
|
||||
{
|
||||
PassportBand band = mIdleMessage.getSiteBand();
|
||||
|
||||
if( band != PassportBand.BAND_UNKNOWN )
|
||||
{
|
||||
int base = band.getBase();
|
||||
|
||||
freq = getFrequency( base, channel );
|
||||
}
|
||||
}
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
switch( getMessageType() )
|
||||
{
|
||||
case SY_IDLE:
|
||||
sb.append( "IDLE SITE:" );
|
||||
sb.append( format( getSite(), 3 ) );
|
||||
sb.append( " NEIGHBOR:" );
|
||||
sb.append( format( getFree(), 3 ) );
|
||||
sb.append( "/" );
|
||||
sb.append( getFreeFrequencyFormatted() );
|
||||
break;
|
||||
case CA_PAGE:
|
||||
sb.append( "PAGING TG:" );
|
||||
sb.append( format( getTalkgroupID(), 5 ) );
|
||||
sb.append( "/" );
|
||||
Alias pageAlias = getTalkgroupIDAlias();
|
||||
if( pageAlias != null )
|
||||
{
|
||||
sb.append( pageAlias.getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( sUNKNOWN );
|
||||
}
|
||||
sb.append( " SITE:" );
|
||||
sb.append( format( getSite(), 3 ) );
|
||||
sb.append( " CHAN:" );
|
||||
sb.append( format( getLCN(), 4 ) );
|
||||
sb.append( "/" );
|
||||
sb.append( getLCNFrequencyFormatted() );
|
||||
sb.append( " FREE:" );
|
||||
sb.append( format( getFree(), 3 ) );
|
||||
sb.append( "/" );
|
||||
sb.append( getFreeFrequencyFormatted() );
|
||||
break;
|
||||
case CA_STRT:
|
||||
sb.append( "CALL TG:" );
|
||||
sb.append( format( getTalkgroupID(), 5 ) );
|
||||
sb.append( "/" );
|
||||
Alias startAlias = getTalkgroupIDAlias();
|
||||
if( startAlias != null )
|
||||
{
|
||||
sb.append( startAlias.getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( sUNKNOWN );
|
||||
}
|
||||
sb.append( " SITE:" );
|
||||
sb.append( format( getSite(), 3 ) );
|
||||
sb.append( " CHAN:" );
|
||||
sb.append( format( getLCN(), 4 ) );
|
||||
sb.append( "/" );
|
||||
sb.append( getLCNFrequencyFormatted() );
|
||||
sb.append( " FREE:" );
|
||||
sb.append( format( getFree(), 3 ) );
|
||||
sb.append( "/" );
|
||||
sb.append( getFreeFrequencyFormatted() );
|
||||
break;
|
||||
case DA_STRT:
|
||||
sb.append( "** DATA TG:" );
|
||||
sb.append( format( getTalkgroupID(), 5 ) );
|
||||
sb.append( "/" );
|
||||
Alias dataStartAlias = getTalkgroupIDAlias();
|
||||
if( dataStartAlias != null )
|
||||
{
|
||||
sb.append( dataStartAlias.getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( sUNKNOWN );
|
||||
}
|
||||
sb.append( " SITE:" );
|
||||
sb.append( format( getSite(), 3 ) );
|
||||
sb.append( " CHAN:" );
|
||||
sb.append( format( getLCN(), 4 ) );
|
||||
sb.append( "/" );
|
||||
sb.append( getLCNFrequencyFormatted() );
|
||||
sb.append( " FREE:" );
|
||||
sb.append( format( getFree(), 3 ) );
|
||||
sb.append( "/" );
|
||||
sb.append( getFreeFrequencyFormatted() );
|
||||
break;
|
||||
case CA_ENDD:
|
||||
sb.append( "END TG:" );
|
||||
sb.append( format( getTalkgroupID(), 5 ) );
|
||||
sb.append( "/" );
|
||||
Alias endAlias = getTalkgroupIDAlias();
|
||||
if( endAlias != null )
|
||||
{
|
||||
sb.append( endAlias.getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( sUNKNOWN );
|
||||
}
|
||||
sb.append( " SITE:" );
|
||||
sb.append( format( getSite(), 3 ) );
|
||||
sb.append( " CHAN:" );
|
||||
sb.append( format( getLCN(), 4 ) );
|
||||
sb.append( "/" );
|
||||
sb.append( getLCNFrequencyFormatted() );
|
||||
sb.append( " FREE:" );
|
||||
sb.append( format( getFree(), 3 ) );
|
||||
sb.append( "/" );
|
||||
sb.append( getFreeFrequencyFormatted() );
|
||||
break;
|
||||
case ID_RDIO:
|
||||
sb.append( "MOBILE ID MIN:" );
|
||||
sb.append( getMobileID() );
|
||||
sb.append( "/" );
|
||||
Alias mobileIDAlias = getMobileIDAlias();
|
||||
|
||||
if( mobileIDAlias != null )
|
||||
{
|
||||
sb.append( mobileIDAlias.getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "UNKNOWN" );
|
||||
}
|
||||
sb.append( " FREE:" );
|
||||
sb.append( format( getFree(), 3 ) );
|
||||
sb.append( "/" );
|
||||
sb.append( getFreeFrequencyFormatted() );
|
||||
break;
|
||||
case ID_TGAS:
|
||||
sb.append( "ASSIGN TALKGROUP:" );
|
||||
sb.append( format( getTalkgroupID(), 5 ) );
|
||||
sb.append( "/" );
|
||||
Alias assignAlias = getTalkgroupIDAlias();
|
||||
if( assignAlias != null )
|
||||
{
|
||||
sb.append( assignAlias.getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( sUNKNOWN );
|
||||
}
|
||||
sb.append( " SITE:" );
|
||||
sb.append( format( getSite(), 3 ) );
|
||||
sb.append( " CHAN:" );
|
||||
sb.append( format( getLCN(), 4 ) );
|
||||
sb.append( "/" );
|
||||
sb.append( getLCNFrequencyFormatted() );
|
||||
break;
|
||||
case RA_REGI:
|
||||
sb.append( "RADIO REGISTER TG: " );
|
||||
sb.append( format( getTalkgroupID(), 5 ) );
|
||||
sb.append( "/" );
|
||||
Alias regAlias = getTalkgroupIDAlias();
|
||||
if( regAlias != null )
|
||||
{
|
||||
sb.append( regAlias.getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( sUNKNOWN );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sb.append( "UNKNOWN SITE:" );
|
||||
sb.append( format( getSite(), 3 ) );
|
||||
sb.append( " CHAN:" );
|
||||
sb.append( format( getLCN(), 4 ) );
|
||||
sb.append( "/" );
|
||||
sb.append( getLCNFrequencyFormatted() );
|
||||
sb.append( " FREE:" );
|
||||
int free = getFree();
|
||||
sb.append( format( free, 3 ) );
|
||||
if( free > 0 && free < 896 )
|
||||
{
|
||||
sb.append( "/" );
|
||||
sb.append( getFreeFrequencyFormatted() );
|
||||
}
|
||||
sb.append( " TYP:" );
|
||||
sb.append( format( getMessageTypeNumber(), 2 ) );
|
||||
sb.append( " TG:" );
|
||||
sb.append( format( getTalkgroupID(), 5 ) );
|
||||
break;
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( mSDF.format( mTimeReceived ) );
|
||||
sb.append( " " );
|
||||
sb.append( getMessage() );
|
||||
pad( sb, 100 );
|
||||
sb.append( mCRC.toString() );
|
||||
pad( sb, 110 );
|
||||
sb.append( " [" );
|
||||
sb.append( mMessage );
|
||||
sb.append( "]" );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorStatus()
|
||||
{
|
||||
return mCRC.getDisplayText();
|
||||
}
|
||||
|
||||
public boolean matches( PassportMessage otherMessage )
|
||||
{
|
||||
return this.getBitSetBuffer().equals( otherMessage.getBitSetBuffer() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plottable getPlottable()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
109
src/decode/passport/PassportMessageProcessor.java
Normal file
109
src/decode/passport/PassportMessageProcessor.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*******************************************************************************
|
||||
* 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 decode.passport;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import message.Message;
|
||||
import message.MessageType;
|
||||
import sample.Broadcaster;
|
||||
import sample.Listener;
|
||||
import alias.AliasList;
|
||||
import bits.BitSetBuffer;
|
||||
|
||||
public class PassportMessageProcessor implements Listener<BitSetBuffer>
|
||||
{
|
||||
private Broadcaster<Message> mBroadcaster = new Broadcaster<Message>();
|
||||
private IdleMessageFinder mIdleFinder = new IdleMessageFinder();
|
||||
private AliasList mAliasList;
|
||||
private PassportMessage mIdleMessage;
|
||||
|
||||
public PassportMessageProcessor( AliasList list )
|
||||
{
|
||||
mAliasList = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( BitSetBuffer buffer )
|
||||
{
|
||||
PassportMessage message;
|
||||
|
||||
if( mIdleMessage != null )
|
||||
{
|
||||
message = new PassportMessage( buffer, mIdleMessage, mAliasList );
|
||||
}
|
||||
else
|
||||
{
|
||||
message = new PassportMessage( buffer, mAliasList );
|
||||
mIdleFinder.receive( message );
|
||||
}
|
||||
|
||||
mBroadcaster.receive( message );
|
||||
}
|
||||
|
||||
public void addMessageListener( Listener<Message> listener )
|
||||
{
|
||||
mBroadcaster.addListener( listener );
|
||||
}
|
||||
|
||||
public void removeMessageListener( Listener<Message> listener )
|
||||
{
|
||||
mBroadcaster.removeListener( listener );
|
||||
}
|
||||
|
||||
public class IdleMessageFinder
|
||||
{
|
||||
public HashMap<String,Integer> mMessageCounts =
|
||||
new HashMap<String,Integer>();
|
||||
|
||||
public boolean mIdleMessageFound = false;
|
||||
|
||||
public IdleMessageFinder()
|
||||
{
|
||||
}
|
||||
|
||||
public void receive( PassportMessage message )
|
||||
{
|
||||
if( !mIdleMessageFound &&
|
||||
message.isValid() &&
|
||||
message.getMessageType() == MessageType.SY_IDLE )
|
||||
{
|
||||
if( mMessageCounts.containsKey( message.getBinaryMessage() ) )
|
||||
{
|
||||
int count = mMessageCounts.get( message.getBinaryMessage() );
|
||||
|
||||
if( count >= 3 )
|
||||
{
|
||||
mIdleMessageFound = true;
|
||||
mIdleMessage = message;
|
||||
mMessageCounts = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
count++;
|
||||
mMessageCounts.put( message.getBinaryMessage(), count );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mMessageCounts.put( message.getBinaryMessage(), 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
255
src/decode/passport/PassportPanel.java
Normal file
255
src/decode/passport/PassportPanel.java
Normal file
@@ -0,0 +1,255 @@
|
||||
/*******************************************************************************
|
||||
* 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 decode.passport;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
|
||||
import settings.ColorSetting;
|
||||
import settings.Setting;
|
||||
import settings.SettingsManager;
|
||||
import alias.Alias;
|
||||
import controller.channel.Channel;
|
||||
import controller.state.ChannelState.ChangedAttribute;
|
||||
import controller.state.ChannelStatePanel;
|
||||
|
||||
public class PassportPanel extends ChannelStatePanel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private JLabel mStateLabel;
|
||||
private JLabel mSourceLabel;
|
||||
private JLabel mChannelLabel;
|
||||
|
||||
private JLabel mProtocol = new JLabel( "Passport" );
|
||||
private JLabel mToTalkgroup = new JLabel();
|
||||
private JLabel mToTalkgroupAlias = new JLabel();
|
||||
|
||||
private JLabel mFromTalkgroupType = new JLabel( " " );
|
||||
private JLabel mFromTalkgroup = new JLabel();
|
||||
private JLabel mFromTalkgroupAlias = new JLabel();
|
||||
|
||||
private SettingsManager mSettingsManager;
|
||||
|
||||
public PassportPanel( SettingsManager settingsManager, Channel channel )
|
||||
{
|
||||
super( channel );
|
||||
|
||||
mSettingsManager = settingsManager;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
super.dispose();
|
||||
mSettingsManager = null;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
mStateLabel = new JLabel( mChannel.getProcessingChain().
|
||||
getChannelState().getState().getDisplayValue() );
|
||||
mStateLabel.setFont( mFontDecoder );
|
||||
mStateLabel.setForeground( mColorLabelDecoder );
|
||||
|
||||
mSourceLabel = new JLabel( mChannel.getSourceConfiguration().getDescription() );
|
||||
mSourceLabel.setFont( mFontDetails );
|
||||
mSourceLabel.setForeground( mColorLabelDetails );
|
||||
|
||||
mChannelLabel = new JLabel( mChannel.getChannelDisplayName() );
|
||||
mChannelLabel.setFont( mFontDetails );
|
||||
mChannelLabel.setForeground( mColorLabelDetails );
|
||||
|
||||
mProtocol.setFont( mFontDecoder );
|
||||
mProtocol.setForeground( mColorLabelDecoder );
|
||||
|
||||
mToTalkgroup.setFont( mFontDecoder );
|
||||
mToTalkgroup.setForeground( mColorLabelDecoder );
|
||||
|
||||
mToTalkgroupAlias.setFont( mFontDecoder );
|
||||
mToTalkgroupAlias.setForeground( mColorLabelDecoder );
|
||||
|
||||
mFromTalkgroupType.setFont( mFontDecoder );
|
||||
mFromTalkgroupType.setForeground( mColorLabelDecoder );
|
||||
|
||||
mFromTalkgroup.setFont( mFontDecoder );
|
||||
mFromTalkgroup.setForeground( mColorLabelDecoder );
|
||||
|
||||
mFromTalkgroupAlias.setFont( mFontDecoder );
|
||||
mFromTalkgroupAlias.setForeground( mColorLabelDecoder );
|
||||
|
||||
add( mStateLabel );
|
||||
add( mSourceLabel );
|
||||
add( mChannelLabel, "wrap" );
|
||||
|
||||
add( mProtocol );
|
||||
add( mToTalkgroup );
|
||||
add( mToTalkgroupAlias, "wrap" );
|
||||
|
||||
add( mFromTalkgroupType );
|
||||
add( mFromTalkgroup );
|
||||
add( mFromTalkgroupAlias, "wrap" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( final ChangedAttribute changedAttribute )
|
||||
{
|
||||
EventQueue.invokeLater( new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
PassportChannelState state = (PassportChannelState)getChannel()
|
||||
.getProcessingChain().getChannelState();
|
||||
|
||||
|
||||
switch( changedAttribute )
|
||||
{
|
||||
case CHANNEL_STATE:
|
||||
mStateLabel.setText( state.getState().getDisplayValue() );
|
||||
break;
|
||||
case SOURCE:
|
||||
mSourceLabel.setText( mChannel.getSourceConfiguration()
|
||||
.getDescription() );
|
||||
break;
|
||||
case CHANNEL_NAME:
|
||||
case SITE_NAME:
|
||||
case SYSTEM_NAME:
|
||||
mChannelLabel.setText( mChannel.getChannelDisplayName() );
|
||||
break;
|
||||
case TO_TALKGROUP:
|
||||
mToTalkgroup.setText( state.getTalkgroup() );
|
||||
break;
|
||||
case TO_TALKGROUP_ALIAS:
|
||||
Alias toAlias = state.getTalkgroupAlias();
|
||||
|
||||
if( toAlias != null )
|
||||
{
|
||||
mToTalkgroupAlias.setText( toAlias.getName() );
|
||||
|
||||
mToTalkgroupAlias.setIcon( mSettingsManager
|
||||
.getImageIcon( toAlias.getIconName(), 12 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mToTalkgroupAlias.setText( null );
|
||||
mToTalkgroupAlias.setIcon( null );
|
||||
}
|
||||
break;
|
||||
case FROM_TALKGROUP:
|
||||
String mid = state.getMobileID();
|
||||
|
||||
mFromTalkgroup.setText( state.getMobileID() );
|
||||
|
||||
if( mid != null )
|
||||
{
|
||||
mFromTalkgroupType.setText( "Mobile ID" );
|
||||
}
|
||||
else
|
||||
{
|
||||
mFromTalkgroupType.setText( " " );
|
||||
}
|
||||
break;
|
||||
case FROM_TALKGROUP_ALIAS:
|
||||
Alias fromAlias = state.getMobileIDAlias();
|
||||
|
||||
if( fromAlias != null )
|
||||
{
|
||||
mFromTalkgroupAlias.setText( fromAlias.getName() );
|
||||
|
||||
mFromTalkgroupAlias.setIcon( mSettingsManager
|
||||
.getImageIcon( fromAlias.getIconName(), 12 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mFromTalkgroupAlias.setText( null );
|
||||
mFromTalkgroupAlias.setIcon( null );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void settingChanged( Setting setting )
|
||||
{
|
||||
super.settingChanged( setting );
|
||||
|
||||
if( setting instanceof ColorSetting )
|
||||
{
|
||||
ColorSetting colorSetting = (ColorSetting)setting;
|
||||
|
||||
switch( colorSetting.getColorSettingName() )
|
||||
{
|
||||
case CHANNEL_STATE_LABEL_DECODER:
|
||||
if( mColorLabelDecoder != null )
|
||||
{
|
||||
if( mStateLabel != null )
|
||||
{
|
||||
mStateLabel.setForeground( mColorLabelDecoder );
|
||||
}
|
||||
if( mProtocol != null )
|
||||
{
|
||||
mProtocol.setForeground( mColorLabelDecoder );
|
||||
}
|
||||
if( mToTalkgroup != null )
|
||||
{
|
||||
mToTalkgroup.setForeground( mColorLabelDecoder );
|
||||
}
|
||||
if( mToTalkgroupAlias != null )
|
||||
{
|
||||
mToTalkgroupAlias.setForeground( mColorLabelDecoder );
|
||||
}
|
||||
if( mFromTalkgroupType != null )
|
||||
{
|
||||
mFromTalkgroupType.setForeground( mColorLabelDecoder );
|
||||
}
|
||||
if( mFromTalkgroup != null )
|
||||
{
|
||||
mFromTalkgroup.setForeground( mColorLabelDecoder );
|
||||
}
|
||||
if( mFromTalkgroupAlias != null )
|
||||
{
|
||||
mFromTalkgroupAlias.setForeground( mColorLabelDecoder );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_STATE_LABEL_DETAILS:
|
||||
if( mColorLabelDetails != null )
|
||||
{
|
||||
if( mSourceLabel != null )
|
||||
{
|
||||
mSourceLabel.setForeground( mColorLabelDetails );
|
||||
}
|
||||
if( mChannelLabel != null )
|
||||
{
|
||||
mChannelLabel.setForeground( mColorLabelDetails );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user