Initial code check in continued

This commit is contained in:
dennis.sheirer
2014-04-26 19:48:24 +00:00
parent 960a6f9952
commit 3dfedcf8d1
474 changed files with 76613 additions and 0 deletions

View File

@@ -0,0 +1,171 @@
/*******************************************************************************
* 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.mpt1327;
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 MPT1327ActivitySummary implements ActivitySummaryProvider,
Listener<Message>
{
private static final int sINT_NULL_VALUE = -1;
private AliasList mAliasList;
private TreeSet<String> mIdents = new TreeSet<String>();
private int mSite;
/**
* 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 MPT1327ActivitySummary( AliasList list )
{
mAliasList = list;
}
/**
* Cleanup method
*/
public void dispose()
{
mIdents.clear();
}
@Override
public void receive( Message message )
{
if( message instanceof MPT1327Message )
{
MPT1327Message mpt = ((MPT1327Message)message);
if( mpt.isValid() )
{
switch( mpt.getMessageType() )
{
case ACK:
mIdents.add( mpt.getFromID() );
break;
case ACKI:
mIdents.add( mpt.getFromID() );
mIdents.add( mpt.getToID() );
break;
case ALH:
mSite = mpt.getSiteID();
break;
case GTC:
if( mpt.hasFromID() )
{
mIdents.add( mpt.getFromID() );
}
if( mpt.hasToID() )
{
mIdents.add( mpt.getToID() );
}
break;
}
}
}
}
@Override
public String getSummary()
{
StringBuilder sb = new StringBuilder();
sb.append( "Activity Summary\n" );
sb.append( "Decoder:\tMPT-1327\n" );
sb.append( "Site:\t" );
if( mSite != 0 )
{
sb.append( mSite );
if( mAliasList != null )
{
Alias siteAlias = mAliasList.getSiteID( mSite );
if( siteAlias != null )
{
sb.append( " " );
sb.append( siteAlias.getName() );
sb.append( "\n" );
}
}
sb.append( "Network:\t" );
if( ( mSite & 0x4000 ) == 0x4000 )
{
sb.append( "National #" );
int net = (int)Long.rotateRight( ( mSite & 0x3000 ) , 12 );
sb.append( net );
sb.append( "\n" );
}
else
{
sb.append( "Regional\n" );
}
}
else
{
sb.append( "Unknown\n" );
}
sb.append( "\n" );
sb.append( "Talkgroups\n" );
if( mIdents.isEmpty() )
{
sb.append( " None\n" );
}
else
{
Iterator<String> it = mIdents.iterator();
while( it.hasNext() )
{
String ident = it.next();
sb.append( " " );
sb.append( ident );
sb.append( " " );
Alias alias = mAliasList.getMPT1327Alias( ident );
if( alias != null )
{
sb.append( alias.getName() );
}
sb.append( "\n" );
}
}
return sb.toString();
}
}

View File

@@ -0,0 +1,154 @@
/*******************************************************************************
* 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.mpt1327;
import alias.Alias;
import alias.AliasList;
import controller.activity.CallEvent;
import decode.DecoderType;
public class MPT1327CallEvent extends CallEvent
{
private int mChannel;
private int mFrequency;
public MPT1327CallEvent( CallEventType callEventType,
AliasList aliasList,
String fromID,
String toID,
int channel,
int frequency,
String details )
{
super( DecoderType.MPT1327, callEventType,
aliasList, fromID, toID, details );
mChannel = channel;
mFrequency = frequency;
}
private Alias getAlias( String mpt1327Talkgroup )
{
if( hasAliasList() )
{
return getAliasList().getMPT1327Alias( mpt1327Talkgroup );
}
return null;
}
@Override
public Alias getFromIDAlias()
{
return getAlias( 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 MPT1327CallEvent build()
{
return new MPT1327CallEvent( this );
}
}
/**
* Private constructor for the builder
*/
private MPT1327CallEvent( Builder builder )
{
this( builder.mCallEventType,
builder.mAliasList,
builder.mFromID,
builder.mToID,
builder.mChannel,
builder.mFrequency,
builder.mDetails );
}
}

View File

@@ -0,0 +1,346 @@
/*******************************************************************************
* 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.mpt1327;
import message.Message;
import sample.Listener;
import source.config.SourceConfigTuner;
import alias.AliasList;
import audio.SquelchListener;
import audio.SquelchListener.SquelchState;
import controller.activity.CallEvent.CallEventType;
import controller.channel.Channel;
import controller.channel.Channel.ChannelType;
import controller.channel.ChannelMap;
import controller.channel.ProcessingChain;
import controller.state.AuxChannelState;
import controller.state.ChannelState;
import decode.config.DecodeConfigMPT1327;
public class MPT1327ChannelState extends ChannelState
{
private int mSite;
private String mFromTalkgroup;
private String mToTalkgroup;
private int mChannelNumber;
private ChannelType mChannelType;
private ChannelMap mChannelMap;
private MPT1327ActivitySummary mActivitySummary;
public MPT1327ChannelState( ProcessingChain processingChain,
AliasList aliasList,
ChannelMap channelMap )
{
super( processingChain, aliasList );
mActivitySummary = new MPT1327ActivitySummary( aliasList );
mChannelMap = channelMap;
mChannelType = processingChain.getChannel().getChannelType();
}
public void dispose()
{
super.dispose();
mActivitySummary.dispose();
mActivitySummary = null;
}
@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
public void receive( Message message )
{
super.receive( message );
if( message instanceof MPT1327Message )
{
mActivitySummary.receive( message );
MPT1327Message mpt = (MPT1327Message)message;
if( mpt.isValid() )
{
switch( mpt.getMessageType() )
{
case AHYC:
mCallEventModel.add(
new MPT1327CallEvent.Builder( CallEventType.SDM )
.aliasList( getProcessingChain().getAliasList() )
.channel( mChannelNumber )
.details( "Short Data Message" )
.frequency( mChannelMap.getFrequency( mChannelNumber ) )
.from( mpt.getFromID() )
.to( mpt.getToID() )
.build() );
break;
case AHYQ:
mCallEventModel.add(
new MPT1327CallEvent.Builder( CallEventType.STATUS )
.aliasList( getProcessingChain().getAliasList() )
.channel( mChannelNumber )
.details( mpt.getStatusMessage() )
.frequency( mChannelMap.getFrequency( mChannelNumber ) )
.from( mpt.getFromID() )
.to( mpt.getToID() )
.build() );
break;
case ALH:
int sys = mpt.getSiteID();
if( sys != 0 && sys != mSite )
{
mSite = sys;
broadcastChange( ChangedAttribute.CHANNEL_SITE_NUMBER );
}
setState( State.CONTROL );
break;
case GTC:
int channelNumber = mpt.getChannel();
if( !getProcessingChain().getChannel()
.hasTrafficChannel( channelNumber ) )
{
String aliasListName = mProcessingChain
.getChannel().getAliasListName();
Channel traffic = getTrafficChannel( channelNumber,
aliasListName );
/* Set the system and site to same as control channel */
traffic.setSystem( getProcessingChain().getChannel()
.getSystem(), false );
traffic.setSite( getProcessingChain().getChannel()
.getSite(), false );
/* Add the traffic channel to the parent control channel */
getProcessingChain().getChannel()
.addTrafficChannel( channelNumber, traffic );
/* Start the traffic channel */
traffic.setEnabled( true );
/* Set traffic channel state info */
MPT1327ChannelState trafficState =
(MPT1327ChannelState)traffic
.getProcessingChain().getChannelState();
MPT1327ChannelState controlState =
(MPT1327ChannelState)getProcessingChain()
.getChannelState();
trafficState.setChannelMap( controlState.getChannelMap() );
trafficState.setChannelNumber( channelNumber );
trafficState.setFromTalkgroup( mpt.getFromID() );
trafficState.setToTalkgroup( mpt.getToID() );
/* Add this control channel as message listener on the
* traffic channel so we can receive call tear-down
* messages */
traffic.addListener( (Listener<Message>)this );
CallEventType type = traffic.isProcessing() ?
CallEventType.CALL_START :
CallEventType.CALL_START_NO_TUNER;
/*
* Set the traffic channel's call event model to
* share the control channel's call event model
*/
traffic.getProcessingChain().getChannelState()
.setCallEventModel( mCallEventModel );
mCallEventModel.add(
new MPT1327CallEvent.Builder( type )
.aliasList( traffic.getProcessingChain().getAliasList() )
.channel( channelNumber )
.frequency( mChannelMap.getFrequency( channelNumber ) )
.from( mpt.getFromID() )
.to( mpt.getToID() )
.build() );
}
int frequency = mChannelMap.getFrequency( channelNumber );
break;
case CLEAR:
case MAINT:
if( mChannelType == ChannelType.TRAFFIC )
{
fade( CallEventType.CALL_END );
}
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 MPT1327CallEvent.Builder( type )
.aliasList( getAliasList() )
.channel( mChannelNumber )
.frequency( mChannelMap.getFrequency( mChannelNumber ) )
.from( mFromTalkgroup )
.to( mToTalkgroup )
.build() );
}
super.fade( type );
}
/**
* Make the ConventionalChannelState always unsquelched
*/
public void addListener( SquelchListener listener )
{
super.addListener( listener );
super.setSquelchState( SquelchState.UNSQUELCH );
}
public void reset()
{
mFromTalkgroup = null;
broadcastChange( ChangedAttribute.FROM_TALKGROUP );
mToTalkgroup = null;
broadcastChange( ChangedAttribute.TO_TALKGROUP );
super.reset();
}
public int getSite()
{
return mSite;
}
public ChannelMap getChannelMap()
{
return mChannelMap;
}
public void setChannelMap( ChannelMap channelMap )
{
mChannelMap = channelMap;
}
public String getFromTalkgroup()
{
return mFromTalkgroup;
}
/**
* Set the talkgroup. This is used primarily for traffic channels since
* the talkgroup will already have been identified prior to the traffic
* channel being created.
*/
public void setFromTalkgroup( String fromTalkgroup )
{
mFromTalkgroup = fromTalkgroup;
broadcastChange( ChangedAttribute.FROM_TALKGROUP );
}
public String getToTalkgroup()
{
return mToTalkgroup;
}
/**
* Set the talkgroup. This is used primarily for traffic channels since
* the talkgroup will already have been identified prior to the traffic
* channel being created.
*/
public void setToTalkgroup( String toTalkgroup )
{
mToTalkgroup = toTalkgroup;
broadcastChange( ChangedAttribute.TO_TALKGROUP );
}
public int getChannelNumber()
{
return mChannelNumber;
}
/**
* Set the channel number. This is used primarily for traffic channels since
* the channel will already have been identified prior to the traffic
* channel being created.
*/
public void setChannelNumber( int channel )
{
mChannelNumber = channel;
broadcastChange( ChangedAttribute.CHANNEL_NUMBER );
}
public String getAliasListName()
{
return mProcessingChain.getChannel().getAliasListName();
}
private Channel getTrafficChannel( int channelNumber, String aliasListName )
{
Channel traffic = new Channel( "Traffic Channel " + channelNumber,
ChannelType.TRAFFIC );
traffic.setResourceManager( getProcessingChain().getResourceManager() );
SourceConfigTuner source = new SourceConfigTuner();
int frequency = mChannelMap.getFrequency( channelNumber );
source.setFrequency( frequency );
traffic.setSourceConfiguration( source );
DecodeConfigMPT1327 decode = new DecodeConfigMPT1327();
traffic.setDecodeConfiguration( decode );
traffic.setAliasListName( aliasListName );
return traffic;
}
}

View File

@@ -0,0 +1,283 @@
/*******************************************************************************
* 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.mpt1327;
import instrument.Instrumentable;
import instrument.tap.Tap;
import instrument.tap.stream.BinaryTap;
import instrument.tap.stream.FloatTap;
import java.util.ArrayList;
import java.util.List;
import sample.Broadcaster;
import source.Source.SampleType;
import alias.AliasList;
import bits.MessageFramer;
import bits.SyncPattern;
import decode.Decoder;
import decode.DecoderType;
import dsp.filter.DCRemovalFilter;
import dsp.filter.FilterFactory;
import dsp.filter.Filters;
import dsp.filter.FloatFIRFilter;
import dsp.filter.FloatHalfBandFilter;
import dsp.filter.Window.WindowType;
import dsp.fsk.FSK2Decoder;
import dsp.fsk.FSK2Decoder.Output;
import dsp.nbfm.NBFMDemodulator;
/**
* MPT1327 Decoder - 1200 baud 2FSK decoder that can process 48k sample rate
* complex or floating point samples and output fully framed MPT1327 control and
* traffic messages.
*/
public class MPT1327Decoder extends Decoder implements Instrumentable
{
/* Determines how quickly the DC remove filter responds */
private static final double sDC_REMOVAL_RATIO = 0.95;
/* Decimated sample rate ( 48,000 / 2 = 24,000 ) feeding the decoder */
private static final int sDECIMATED_SAMPLE_RATE = 24000;
/* Baud or Symbol Rate */
private static final int sSYMBOL_RATE = 1200;
/* Message length -- longest possible message is:
* 4xREVS + 16xSYNC + 64xADD1 + 64xDCW1 + 64xDCW2 + 64xDCW3 + 64xDCW4 */
private static final int sMESSAGE_LENGTH = 350;
/* Instrumentation Taps */
private static final String INSTRUMENT_INPUT = "Tap Point: Input";
private static final String INSTRUMENT_HB1_FILTER_TO_LOW_PASS =
"Tap Point: Half-band Decimation Filter > < Low Pass Filter";
private static final String INSTRUMENT_LOW_PASS_TO_DECODER =
"Tap Point: Low Pass Filter > < Decoder";
private static final String INSTRUMENT_DECODER_TO_FRAMER =
"Tap Point: Decoder > < Sync Detect/Message Framer";
private List<Tap> mAvailableTaps;
private NBFMDemodulator mNBFMDemodulator;
private FloatHalfBandFilter mDecimationFilter;
private FloatFIRFilter mLowPassFilter;
private DCRemovalFilter mDCRemovalFilter;
private FSK2Decoder mFSKDecoder;
private Broadcaster<Boolean> mSymbolBroadcaster;
private MessageFramer mControlMessageFramer;
private MessageFramer mTrafficMessageFramer;
private MPT1327MessageProcessor mMessageProcessor;
public MPT1327Decoder( SampleType sampleType, AliasList aliasList )
{
super( sampleType );
/* If we're receiving complex samples, do FM demodulation and DC removal
* and feed the output back to this decoder */
if( mSourceSampleType == SampleType.COMPLEX )
{
/* I/Q low pass filtering narrow band FM demodulator */
mNBFMDemodulator = new NBFMDemodulator(
FilterFactory.getLowPass( 48000, 4000, 73, WindowType.HAMMING ),
1.0002 );
this.addComplexListener( mNBFMDemodulator );
/* DC removal filter */
mDCRemovalFilter = new DCRemovalFilter( sDC_REMOVAL_RATIO );
if( mNBFMDemodulator != null )
{
mNBFMDemodulator.addListener( mDCRemovalFilter );
mDCRemovalFilter.setListener( this.getFloatReceiver() );
}
}
/* Demodulated float sample processing */
/* Decimation filter - 48000 / 2 = 24000 output */
mDecimationFilter = new FloatHalfBandFilter(
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO, 1.0002 );
addFloatListener( mDecimationFilter );
/* Low pass filter: 2kHz to pass the 1200 & 1800 Hz FSK */
mLowPassFilter = new FloatFIRFilter(
FilterFactory.getLowPass( 24000, //sampleRate,
2000, //passFrequency,
4000, //stopFrequency,
60, //attenuation,
WindowType.HANNING, //windowType,
true ) //forceOddLength
, 2.0 ); //Gain
mDecimationFilter.setListener( mLowPassFilter );
/* 2FSK Decoder with output inverted */
mFSKDecoder = new FSK2Decoder( 24000, 1200, Output.INVERTED );
mLowPassFilter.setListener( mFSKDecoder );
mSymbolBroadcaster = new Broadcaster<Boolean>();
mFSKDecoder.setListener( mSymbolBroadcaster );
/* Message framer for control channel messages */
mControlMessageFramer =
new MessageFramer( SyncPattern.MPT1327_CONTROL.getPattern(),
sMESSAGE_LENGTH );
mSymbolBroadcaster.addListener( mControlMessageFramer );
/* Message framer for traffic channel massages */
mTrafficMessageFramer =
new MessageFramer( SyncPattern.MPT1327_TRAFFIC.getPattern(),
sMESSAGE_LENGTH );
mSymbolBroadcaster.addListener( mTrafficMessageFramer );
/* Fully decoded and framed messages processor */
mMessageProcessor = new MPT1327MessageProcessor( aliasList );
mMessageProcessor.addMessageListener( this );
mControlMessageFramer.addMessageListener( mMessageProcessor );
mTrafficMessageFramer.addMessageListener( mMessageProcessor );
}
@Override
public DecoderType getType()
{
return DecoderType.MPT1327;
}
/**
* Cleanup method
*/
public void dispose()
{
super.dispose();
mSymbolBroadcaster.dispose();
mControlMessageFramer.dispose();
if( mDCRemovalFilter != null )
{
mDCRemovalFilter.dispose();
}
if( mNBFMDemodulator != null )
{
mNBFMDemodulator.dispose();
}
mFSKDecoder.dispose();
mDecimationFilter.dispose();
mLowPassFilter.dispose();
mMessageProcessor.dispose();
mTrafficMessageFramer.dispose();
}
/* Instrumentation Taps */
@Override
public List<Tap> getTaps()
{
if( mAvailableTaps == null )
{
mAvailableTaps = new ArrayList<Tap>();
mAvailableTaps.add(
new FloatTap( INSTRUMENT_INPUT, 0, 1.0f ) );
mAvailableTaps.add(
new FloatTap( INSTRUMENT_HB1_FILTER_TO_LOW_PASS, 0, 0.5f ) );
mAvailableTaps.add(
new FloatTap( INSTRUMENT_LOW_PASS_TO_DECODER, 0, 0.5f ) );
mAvailableTaps.add(
new BinaryTap( INSTRUMENT_DECODER_TO_FRAMER, 0, 0.025f ) );
/* Add the taps from the FSK decoder */
mAvailableTaps.addAll( mFSKDecoder.getTaps() );
}
return mAvailableTaps;
}
@Override
public void addTap( Tap tap )
{
/* Send request to decoder */
mFSKDecoder.addTap( tap );
switch( tap.getName() )
{
case INSTRUMENT_INPUT:
FloatTap inputTap = (FloatTap)tap;
if( mNBFMDemodulator != null )
{
mNBFMDemodulator.addListener( inputTap );
}
else
{
addFloatListener( inputTap );
}
break;
case INSTRUMENT_HB1_FILTER_TO_LOW_PASS:
FloatTap hb1Tap = (FloatTap)tap;
mDecimationFilter.setListener( hb1Tap );
hb1Tap.setListener( mLowPassFilter );
break;
case INSTRUMENT_LOW_PASS_TO_DECODER:
FloatTap lowTap = (FloatTap)tap;
mLowPassFilter.setListener( lowTap );
lowTap.setListener( mFSKDecoder );
break;
case INSTRUMENT_DECODER_TO_FRAMER:
BinaryTap decoderTap = (BinaryTap)tap;
mFSKDecoder.setListener( decoderTap );
decoderTap.setListener( mSymbolBroadcaster );
break;
}
}
@Override
public void removeTap( Tap tap )
{
mFSKDecoder.removeTap( tap );
switch( tap.getName() )
{
case INSTRUMENT_INPUT:
FloatTap inputTap = (FloatTap)tap;
if( mNBFMDemodulator != null )
{
mNBFMDemodulator.removeListener( inputTap );
}
else
{
removeFloatListener( inputTap );
}
break;
case INSTRUMENT_HB1_FILTER_TO_LOW_PASS:
mDecimationFilter.setListener( mLowPassFilter );
break;
case INSTRUMENT_LOW_PASS_TO_DECODER:
mLowPassFilter.setListener( mFSKDecoder );
break;
case INSTRUMENT_DECODER_TO_FRAMER:
mFSKDecoder.setListener( mSymbolBroadcaster );
break;
}
}
}

View File

@@ -0,0 +1,103 @@
/*******************************************************************************
* 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.mpt1327;
import java.util.ArrayList;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import controller.channel.ChannelMap;
import controller.channel.ChannelNode;
import decode.DecodeEditor;
import decode.config.DecodeConfigMPT1327;
import decode.config.DecodeConfiguration;
public class MPT1327Editor extends DecodeEditor
{
private static final long serialVersionUID = 1L;
private JComboBox<ChannelMap> mComboChannelMaps;
private ChannelNode mChannelNode;
public MPT1327Editor( DecodeConfiguration config, ChannelNode channelNode )
{
super( config );
mChannelNode = channelNode;
initGUI();
}
private void initGUI()
{
/**
* ComboBox: Alias Lists
*/
ArrayList<ChannelMap> maps = mChannelNode.getModel().getResourceManager()
.getPlaylistManager().getPlayist().getChannelMapList().getChannelMap();
ChannelMap[] mapArray = maps.toArray( new ChannelMap[ maps.size() ] );
mComboChannelMaps = new JComboBox<ChannelMap>();
mComboChannelMaps.setModel(
new DefaultComboBoxModel<ChannelMap>( mapArray ) );
add( new JLabel( "Channel Map" ), "wrap" );
add( mComboChannelMaps, "wrap" );
reset();
}
@Override
public void save()
{
ChannelMap selected = (ChannelMap)mComboChannelMaps.getSelectedItem();
if( selected != null )
{
((DecodeConfigMPT1327)mConfig).setChannelMapName( selected.getName() );
}
}
@Override
public void reset()
{
String name = ((DecodeConfigMPT1327)mConfig).getChannelMapName();
ChannelMap selected = null;
if( name != null )
{
for( ChannelMap map: mChannelNode.getModel().getResourceManager()
.getPlaylistManager().getPlayist().getChannelMapList()
.getChannelMap() )
{
if( map.getName().equalsIgnoreCase( name ) )
{
selected = map;
}
}
}
mComboChannelMaps.setSelectedItem( selected );
mComboChannelMaps.requestFocus();
mComboChannelMaps.requestFocusInWindow();
}
}

View File

@@ -0,0 +1,986 @@
/*******************************************************************************
* 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.mpt1327;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import map.Plottable;
import message.Message;
import alias.Alias;
import alias.AliasList;
import bits.BitSetBuffer;
import crc.CRC;
import crc.CRCFleetsync;
public class MPT1327Message extends Message
{
private static DecimalFormat mDecimalFormatter = new DecimalFormat("#.#####");
private static SimpleDateFormat mSDF = new SimpleDateFormat( "yyyyMMdd HHmmss" );
//Calendar to use in calculating time hacks
Calendar mCalendar = new GregorianCalendar();
//Message parts are identified in big-endian order for correct translation
private static int BLOCK_1_START = 20;
private static int BLOCK_2_START = 84;
private static int BLOCK_3_START = 148;
private static int BLOCK_4_START = 212;
private static int BLOCK_5_START = 276;
private static int BLOCK_5_END = 340;
private static int[] REVS = { 0,1,2,3 };
private static int[] SYNC = { 4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 };
/* Block 1 Fields */
private static int[] B1_PREFIX = { 21,22,23,24,25,26,27 };
private static int[] B1_IDENT1 = { 28,29,30,31,32,33,34,35,36,37,38,39,40 };
private static int[] B1_IDENT2 = { 53,54,55,56,57,58,59,60,61,62,63,64,65 };
private static int[] B1_GTC_CHAN = { 43,44,45,46,47,48,49,50,51,52 };
private static int[] B1_MESSAGE_TYPE = { 41,42,43,44,45,46,47,48,49 };
private static int[] B1_STATUS_MESSAGE = { 66,67,68,69,70 };
private static int[] B1_SYSTEM_ID = { 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40 };
private static int[] B1_SYSDEF = { 21,22,23,24,25 };
private static int[] B1_CHANNEL = { 35,36,37,38,39,40,41,42,43,44 };
private static int[] B1_TRAFFIC_CHANNEL = { 21,22,23,24,25,26,27,28,29,30 };
private static int[] B1_CONTROL_CHANNEL = { 31,32,33,34,35,36,37,38,39,40 };
private static int[] B1_ADJSITE = { 49,50,51,52 };
/* Block 2 Fields */
private static int[] B2_SYSTEM_ID = { 85,86,87,88,89,90,91,92,93,94,95,96,97,98,99 };
private static int[] B2_PREFIX = { 112,113,114,115,116,117,118 };
private static int[] B2_IDENT2 = { 119,120,121,122,123,124,125,126,127,128,129,130,131 };
private BitSetBuffer mMessage;
private CRC[] mCRC = new CRC[ 5 ];
private AliasList mAliasList;
private MPTMessageType mMessageType;
public MPT1327Message( BitSetBuffer message, AliasList list )
{
mMessage = message;
mAliasList = list;
checkParity( 0, BLOCK_1_START, BLOCK_2_START );
if( isValid() )
{
mMessageType = getMessageType();
switch( mMessageType )
{
/* 1 data block messages */
case CLEAR:
case MAINT:
case MOVE:
break;
/* 2 data block messages */
case AHYQ:
case ALH:
checkParity( 1, BLOCK_2_START, BLOCK_3_START );
break;
/* 3 data block messages */
/* 4 data block messages */
case ACKT:
checkParity( 1, BLOCK_2_START, BLOCK_3_START );
checkParity( 2, BLOCK_3_START, BLOCK_4_START );
checkParity( 3, BLOCK_4_START, BLOCK_5_START );
break;
/* 5 data block messages */
case AHYC:
checkParity( 1, BLOCK_2_START, BLOCK_3_START );
checkParity( 2, BLOCK_3_START, BLOCK_4_START );
checkParity( 3, BLOCK_4_START, BLOCK_5_START );
checkParity( 3, BLOCK_5_START, BLOCK_5_END );
break;
case ACK:
case ACKB:
case ACKE:
case ACKI:
case ACKQ:
case ACKV:
case ACKX:
case AHOY:
case AHYP:
case AHYX:
case ALHD:
case ALHE:
case ALHF:
case ALHR:
case ALHS:
case ALHX:
case BCAST:
case GTC:
case MARK:
break;
default:
break;
}
}
else
{
mMessageType = MPTMessageType.UNKN;
}
}
private void checkParity( int section, int start, int end )
{
mCRC[ section ] = detectAndCorrect( start, end );
}
private CRC detectAndCorrect( int start, int end )
{
BitSet original = mMessage.get( start, end );
CRC retVal = CRCFleetsync.check( original );
//Attempt to correct single-bit errors
if( retVal == CRC.FAILED_PARITY )
{
int[] errorBitPositions = CRCFleetsync.findBitErrors( original );
if( errorBitPositions != null )
{
for( int errorBitPosition: errorBitPositions )
{
mMessage.flip( start + errorBitPosition );
}
retVal = CRC.CORRECTED;
}
}
return retVal;
}
/**
* String representing results of the parity check
*
* [P] = passes parity check
* [f] = fails parity check
* [C] = corrected message
* [-] = message section not present
*/
public String getParity()
{
return "[" + CRC.format( mCRC ) + "]";
}
public boolean isValid()
{
return mCRC[ 0 ] == CRC.PASSED ||
mCRC[ 0 ] == CRC.CORRECTED;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append( mSDF.format( new Date() ) );
sb.append( " MPT1327 " );
sb.append( getParity() );
sb.append( " " );
sb.append( getMessage() );
sb.append( getFiller( sb, 100 ) );
sb.append( " [" + mMessage.toString() + "]" );
return sb.toString();
}
public MPTMessageType getMessageType()
{
int type = mMessage.getInt( B1_MESSAGE_TYPE );
return MPTMessageType.fromNumber( type );
}
public int getSiteID()
{
if( mMessageType == MPTMessageType.BCAST )
{
return mMessage.getInt( B1_SYSTEM_ID );
}
else if( mMessageType == MPTMessageType.ALH )
{
return mMessage.getInt( B2_SYSTEM_ID );
}
else
{
return 0;
}
}
public boolean hasSystemID()
{
return getSiteID() != 0;
}
public SystemDefinition getSystemDefinition()
{
int sysdef = mMessage.getInt( B1_SYSDEF );
return SystemDefinition.fromNumber( sysdef );
}
public int getChannel()
{
switch( mMessageType )
{
case CLEAR:
return mMessage.getInt( B1_TRAFFIC_CHANNEL );
case GTC:
return mMessage.getInt( B1_GTC_CHAN );
default:
return mMessage.getInt( B1_CHANNEL );
}
}
public int getReturnToChannel()
{
if( mMessageType == MPTMessageType.CLEAR )
{
return mMessage.getInt( B1_CONTROL_CHANNEL );
}
else
{
return 0;
}
}
public int getAdjacentSiteSerialNumber()
{
return mMessage.getInt( B1_ADJSITE );
}
public int getPrefix()
{
return mMessage.getInt( B1_PREFIX );
}
public int getBlock2Prefix()
{
return mMessage.getInt( B2_PREFIX );
}
public int getIdent1()
{
return mMessage.getInt( B1_IDENT1 );
}
public int getIdent2()
{
return mMessage.getInt( B1_IDENT2 );
}
public int getBlock2Ident2()
{
return mMessage.getInt( B2_IDENT2 );
}
public String getStatusMessage()
{
int status = mMessage.getInt( B1_STATUS_MESSAGE );
switch( status )
{
case 0:
return "STATUS: Request Speech Call";
case 31:
return "STATUS: Cancel Request Speech Call";
default:
return "STATUS: " + status;
}
}
/**
* Returns spaces to the fill the string builder to ensure length is >= index
*/
public String getFiller( StringBuilder sb, int index )
{
if( sb.length() < index )
{
return String.format( "%" + ( index - sb.length() ) + "s", " " );
}
else
{
return "";
}
}
/**
* Pads spaces onto the end of the value to make it 'places' long
*/
public String pad( String value, int places, String padCharacter )
{
StringBuilder sb = new StringBuilder();
sb.append( value );
while( sb.length() < places )
{
sb.append( padCharacter );
}
return sb.toString();
}
/**
* 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();
}
@Override
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( pad( mMessageType.toString(), 5, " " ) );
switch( mMessageType )
{
case ACK:
sb.append( " MESSAGE ACKNOWLEDGED" );
if( hasFromID() )
{
sb.append( " FROM:" );
sb.append( getFromID() );
}
break;
case ACKI:
sb.append( " SYSTEM:" );
sb.append( format( getSiteID(), 5 ) );
sb.append( " MESSAGE ACKNOWLEDGED - MORE TO FOLLOW" );
if( hasFromID() )
{
sb.append( " FROM:" );
sb.append( getFromID() );
}
if( hasToID() )
{
sb.append( " TO:" );
sb.append( getToID() );
}
break;
case ACKT:
sb.append( " SITE:" );
sb.append( format( getSiteID(), 5 ) );
sb.append( " LONG ACK MESSAGE" );
if( hasFromID() )
{
sb.append( " FROM:" );
sb.append( getFromID() );
}
if( hasToID() )
{
sb.append( " TO:" );
sb.append( getToID() );
}
sb.append( "**********************************" );
break;
case ACKQ:
sb.append( " SYSTEM:" );
sb.append( format( getSiteID(), 5 ) );
sb.append( " CALL QUEUED FROM:" );
if( hasFromID() )
{
sb.append( " FROM:" );
sb.append( getFromID() );
}
if( hasToID() )
{
sb.append( " TO:" );
sb.append( getToID() );
}
break;
case ACKX:
sb.append( " SYSTEM:" );
sb.append( format( getSiteID(), 5 ) );
sb.append( " MESSAGE REJECTED FROM:" );
if( hasFromID() )
{
sb.append( " FROM:" );
sb.append( getFromID() );
}
if( hasToID() )
{
sb.append( " TO:" );
sb.append( getToID() );
}
break;
case AHYC:
/* SDM */
sb.append( " SHORT DATA INVITATION MESSAGE ********* " );
break;
case AHYQ:
/* Status Message */
sb.append( " STATUS MESSAGE" );
if( hasFromID() )
{
sb.append( " FROM:" );
sb.append( getFromID() );
}
if( hasToID() )
{
sb.append( " TO:" );
sb.append( getToID() );
}
sb.append( " " );
sb.append( getStatusMessage() );
break;
case ALH:
case ALHD:
case ALHS:
case ALHE:
case ALHR:
case ALHX:
case ALHF:
sb.append( " SYSTEM:" );
sb.append( format( getSiteID(), 5 ) );
if( hasToID() )
{
sb.append( " ID:" );
sb.append( getToID() );
}
break;
case BCAST:
SystemDefinition sysdef = getSystemDefinition();
sb.append( " " );
sb.append( sysdef.getLabel() );
switch( sysdef )
{
case ANNOUNCE_CONTROL_CHANNEL:
case WITHDRAW_CONTROL_CHANNEL:
sb.append( " CHAN:" );
sb.append( getChannel() );
break;
case BROADCAST_ADJACENT_SITE_CONTROL_CHANNEL_NUMBER:
sb.append( " CHAN:" );
sb.append( getChannel() );
sb.append( " SER:" );
sb.append( getAdjacentSiteSerialNumber() );
//debug
sb.append( " *************************" );
break;
}
break;
case CLEAR:
sb.append( " TRAFFIC CHANNEL:" );
sb.append( getChannel() );
sb.append( " RETURN TO CONTROL CHANNEL:" );
sb.append( getReturnToChannel() );
break;
case GTC:
if( hasFromID() )
{
sb.append( " FROM:" );
sb.append( getFromID() );
}
if( hasToID() )
{
sb.append( " TO:" );
sb.append( getToID() );
}
sb.append( " CHAN:" );
sb.append( getChannel() );
break;
case MAINT:
if( hasToID() )
{
sb.append( " ID:" );
sb.append( getToID() );
}
break;
}
return sb.toString();
}
@Override
public String getBinaryMessage()
{
return mMessage.toString();
}
@Override
public String getProtocol()
{
return "MPT-1327";
}
@Override
public String getEventType()
{
// TODO Auto-generated method stub
return null;
}
@Override
public String getFromID()
{
StringBuilder sb = new StringBuilder();
int ident2 = getIdent2();
IdentType type = IdentType.fromIdent( ident2 );
/* Inter-Prefix - the from and to idents are different prefixes */
if( type == IdentType.IPFIXI )
{
sb.append( format( getBlock2Prefix(), 3 ) );
sb.append( "-" );
sb.append( format( getBlock2Ident2(), 4) );
}
else
{
sb.append( format( getPrefix(), 3 ) );
sb.append( "-" );
sb.append( format( ident2, 4) );
}
return sb.toString();
}
public boolean hasFromID()
{
return getFromID() != null;
}
@Override
public Alias getFromIDAlias()
{
return null;
}
@Override
public String getToID()
{
StringBuilder sb = new StringBuilder();
int prefix = getPrefix();
int ident = getIdent1();
switch( IdentType.fromIdent( ident ) )
{
case USER:
sb.append( format( prefix, 3 ) );
sb.append( "-" );
sb.append( format( ident, 4) );
break;
case IPFIXI:
sb.append( "INTER-PREFIX" );
break;
case ALLI:
sb.append( "ALL RADIOS" );
break;
case PABXI:
sb.append( "PABX EXT" );
break;
case PSTNSI1:
case PSTNSI2:
case PSTNSI3:
case PSTNSI4:
case PSTNSI5:
case PSTNSI6:
case PSTNSI7:
case PSTNSI8:
case PSTNSI9:
case PSTNSI10:
case PSTNSI11:
case PSTNSI12:
case PSTNSI13:
case PSTNSI14:
case PSTNSI15:
sb.append( "PRE-DEFINED PSTN" );
break;
case PSTNGI:
sb.append( "PSTN GATEWAY" );
break;
case TSCI:
sb.append( "CONTROLLER" );
break;
case DIVERTI:
sb.append( "CALL DIVERT" );
break;
}
return sb.toString();
}
public boolean hasToID()
{
return getToID() != null;
}
@Override
public Alias getToIDAlias()
{
if( hasToID() )
{
return mAliasList.getMPT1327Alias( getToID() );
}
else
{
return null;
}
}
@Override
public String getErrorStatus()
{
return getParity();
}
@Override
public Plottable getPlottable()
{
return null;
}
public enum IdentType
{
ALLI( "All Subscribers" ),
DIVERTI( "Divert" ),
DNI( "Data Network Gateway" ),
DUMMYI( "Dummy Ident" ),
INCI( "Include in Call" ),
IPFIXI( "Inter-Prefix" ),
PABXI( "PABX Gateway" ),
PSTNGI( "PSTN Gateway" ),
PSTNSI1( "PSTN or Network 1" ),
PSTNSI2( "PSTN or Network 2" ),
PSTNSI3( "PSTN or Network 3" ),
PSTNSI4( "PSTN or Network 4" ),
PSTNSI5( "PSTN or Network 5" ),
PSTNSI6( "PSTN or Network 6" ),
PSTNSI7( "PSTN or Network 7" ),
PSTNSI8( "PSTN or Network 8" ),
PSTNSI9( "PSTN or Network 9" ),
PSTNSI10( "PSTN or Network 10" ),
PSTNSI11( "PSTN or Network 11" ),
PSTNSI12( "PSTN or Network 12" ),
PSTNSI13( "PSTN or Network 13" ),
PSTNSI14( "PSTN or Network 14" ),
PSTNSI15( "PSTN or Network 15" ),
REGI( "Registration" ),
RESERVED( "Reserved" ),
SDMI( "Short Data Message" ),
SPARE( "Spare" ),
TSCI( "TSC" ),
USER( "Individual or Group Ident" ),
UNKNOWN( "Unknown" );
private String mLabel;
private IdentType( String label )
{
mLabel = label;
}
public String getLabel()
{
return mLabel;
}
public static IdentType fromIdent( int ident )
{
switch( ident )
{
case 0:
return DUMMYI;
case 8101:
return PSTNGI;
case 8102:
return PABXI;
case 8103:
return DNI;
case 8121:
return PSTNSI1;
case 8122:
return PSTNSI2;
case 8123:
return PSTNSI3;
case 8124:
return PSTNSI4;
case 8125:
return PSTNSI5;
case 8126:
return PSTNSI6;
case 8127:
return PSTNSI7;
case 8128:
return PSTNSI8;
case 8129:
return PSTNSI9;
case 8130:
return PSTNSI10;
case 8131:
return PSTNSI11;
case 8132:
return PSTNSI12;
case 8133:
return PSTNSI13;
case 8134:
return PSTNSI14;
case 8135:
return PSTNSI15;
case 8181:
case 8182:
case 8183:
case 8184:
return RESERVED;
case 8185:
return REGI;
case 8186:
return INCI;
case 8187:
return DIVERTI;
case 8188:
return SDMI;
case 8189:
return IPFIXI;
case 8190:
return TSCI;
case 8191:
return ALLI;
default:
if( 1 <= ident && ident <= 8100 )
{
return USER;
}
else if( ( 8104 <= ident && ident <= 8120 ) ||
( 8136 <= ident && ident <= 8180 ) )
{
return SPARE;
}
else
{
return UNKNOWN;
}
}
}
}
public enum SystemDefinition
{
UNKNOWN( "UNKNOWN" ),
ANNOUNCE_CONTROL_CHANNEL( "ANNOUNCE CONTROL CHANNEL" ),
WITHDRAW_CONTROL_CHANNEL( "WITHDRAW CONTROL CHANNEL" ),
SPECIFY_CALL_MAINTENANCE_PARAMETERS( "CALL MAINT PARAMETERS" ),
SPECIFY_REGISTRATION_PARAMETERS( "REGISTRATION PARAMETERS" ),
BROADCAST_ADJACENT_SITE_CONTROL_CHANNEL_NUMBER( "NEIGHBOR" ),
VOTE_NOW_ADVICE( "VOTE NOW" );
private String mLabel;
private SystemDefinition( String label )
{
mLabel = label;
}
public String getLabel()
{
return mLabel;
}
public static SystemDefinition fromNumber( int number )
{
switch( number )
{
case 0:
return ANNOUNCE_CONTROL_CHANNEL;
case 1:
return WITHDRAW_CONTROL_CHANNEL;
case 2:
return SPECIFY_CALL_MAINTENANCE_PARAMETERS;
case 3:
return SPECIFY_REGISTRATION_PARAMETERS;
case 4:
return BROADCAST_ADJACENT_SITE_CONTROL_CHANNEL_NUMBER;
case 5:
return VOTE_NOW_ADVICE;
default:
return UNKNOWN;
}
}
}
public enum MPTMessageType
{
UNKN( -1, "Unknown" ),
GTC( 0, "GTC - Goto Channel" ),
ALH( 256, "ALH - Aloha" ),
ALHS( 257, "ALHS - Standard Data Excluded" ),
ALHD( 258, "ALHD - Simple Calls Excluded" ),
ALHE( 259, "ALHE - Emergency Calls Only" ),
ALHR( 260, "ALHR - Emergency or Registration" ),
ALHX( 261, "ALHX - Registration Excluded" ),
ALHF( 262, "ALHF - Fallback Mode" ),
ACK( 264, "ACK - Acknowledge" ),
ACKI( 265, "ACKI - More To Follow" ),
ACKQ( 266, "ACKQ - Call Queued" ),
ACKX( 267, "ACKX - Message Rejected" ),
ACKV( 268, "ACKV - Called Unit Unavailable" ),
ACKE( 269, "ACKE - Emergency" ),
ACKT( 270, "ACKT - Try On Given Address" ),
ACKB( 271, "ACKB - Call Back/Negative Ack" ),
AHOY( 272, "AHOY - General Availability Check" ),
AHYX( 274, "AHYX - Cancel Alert/Waiting Status" ),
AHYP( 277, "AHYP - Called Unit Presence Monitoring" ),
AHYQ( 278, "AHYQ - Status Message" ),
AHYC( 279, "AHYC - Short Data Message" ),
MARK( 280, "MARK - Control Channel Marker" ),
MAINT(281, "MAINT - Call Maintenance Message"),
CLEAR(282, "CLEAR - Down From Allocated Channel" ),
MOVE( 283, "MOVE - To Specified Channel" ),
BCAST(284, "BCAST - System Parameters" );
/* There are more to fill in here */
private int mNumber;
private String mDescription;
private MPTMessageType( int number, String description )
{
mNumber = number;
mDescription = description;
}
public int getMessageNumber()
{
return mNumber;
}
public String getDescription()
{
return mDescription;
}
public static MPTMessageType fromNumber( int number )
{
if( number < 256 )
{
return GTC;
}
switch( number )
{
case 256:
return ALH;
case 257:
return ALHS;
case 258:
return ALHD;
case 259:
return ALHE;
case 260:
return ALHR;
case 261:
return ALHX;
case 262:
return ALHF;
case 264:
return ACK;
case 265:
return ACKI;
case 266:
return ACKQ;
case 267:
return ACKX;
case 268:
return ACKV;
case 269:
return ACKE;
case 270:
return ACKT;
case 271:
return ACKB;
case 272:
return AHOY;
case 274:
return AHYX;
case 277:
return AHYP;
case 278:
return AHYQ;
case 279:
return AHYC;
case 280:
return MARK;
case 281:
return MAINT;
case 282:
return CLEAR;
case 283:
return MOVE;
case 284:
return BCAST;
default:
return UNKN;
}
}
}
}

View File

@@ -0,0 +1,59 @@
/*******************************************************************************
* 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.mpt1327;
import message.Message;
import sample.Broadcaster;
import sample.Listener;
import alias.AliasList;
import bits.BitSetBuffer;
public class MPT1327MessageProcessor implements Listener<BitSetBuffer>
{
private Broadcaster<Message> mBroadcaster = new Broadcaster<Message>();
private AliasList mAliasList;
public MPT1327MessageProcessor( AliasList list )
{
mAliasList = list;
}
public void dispose()
{
mBroadcaster.dispose();
}
@Override
public void receive( BitSetBuffer buffer )
{
MPT1327Message message = new MPT1327Message( buffer, mAliasList );
mBroadcaster.receive( message );
}
public void addMessageListener( Listener<Message> listener )
{
mBroadcaster.addListener( listener );
}
public void removeMessageListener( Listener<Message> listener )
{
mBroadcaster.removeListener( listener );
}
}

View File

@@ -0,0 +1,282 @@
/*******************************************************************************
* 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.mpt1327;
import java.awt.EventQueue;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import settings.ColorSetting;
import settings.Setting;
import alias.Alias;
import alias.AliasList;
import controller.channel.Channel;
import controller.state.ChannelState.ChangedAttribute;
import controller.state.ChannelStatePanel;
public class MPT1327Panel extends ChannelStatePanel
{
private static final long serialVersionUID = 1L;
private JLabel mProtocol;
private JLabel mSourceLabel;
private JLabel mChannelLabel;
private JLabel mStateLabel;
private JLabel mTalkgroup;
private JLabel mTalkgroupAlias;
private JLabel mSiteLabel;
private JLabel mSite;
private JLabel mSiteAliasLabel;
private MPT1327ChannelState mState;
private AliasList mAliasList;
public MPT1327Panel( Channel channel )
{
super( channel );
mState = (MPT1327ChannelState)channel.getProcessingChain().getChannelState();
mState.addListener( this );
mAliasList = mState.getAliasList();
init();
}
public void dispose()
{
super.dispose();
mState = null;
mAliasList = null;
}
public void init()
{
mProtocol = new JLabel( "MPT1327" );
mProtocol.setFont( mFontDecoder );
mProtocol.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 );
mStateLabel = new JLabel( mChannel.getProcessingChain().
getChannelState().getState().getDisplayValue() );
mStateLabel.setFont( mFontDecoder );
mStateLabel.setForeground( mColorLabelDecoder );
mTalkgroup = new JLabel( mState.getFromTalkgroup() );
mTalkgroup.setFont( mFontDecoder );
mTalkgroup.setForeground( mColorLabelDecoder );
mTalkgroupAlias = new JLabel();
mTalkgroupAlias.setFont( mFontDecoder );
mTalkgroupAlias.setForeground( mColorLabelDecoder );
Alias alias = getTalkgroupAlias( mState.getFromTalkgroup() );
if( alias != null )
{
mTalkgroupAlias.setText( alias.getName() );
mTalkgroupAlias.setIcon( getIcon( alias ) );
}
mSiteLabel = new JLabel( "Site:" );
mSiteLabel.setFont( mFontDetails );
mSiteLabel.setForeground( mColorLabelDetails );
mSite = new JLabel( String.valueOf( mState.getSite() ) );
mSite.setFont( mFontDecoder );
mSite.setForeground( mColorLabelDecoder );
mSiteAliasLabel = new JLabel();
mSiteAliasLabel.setFont( mFontDecoder );
mSiteAliasLabel.setForeground( mColorLabelDecoder );
Alias siteAlias = getSiteAlias( mState.getSite() );
if( siteAlias != null )
{
mSiteAliasLabel.setText( siteAlias.getName() );
}
add( mProtocol );
add( mSourceLabel );
add( mChannelLabel, "wrap" );
add( mStateLabel );
add( mTalkgroup );
add( mTalkgroupAlias, "wrap" );
add( mSiteLabel );
add( mSite );
add( mSiteAliasLabel, "wrap" );
}
@Override
public void receive( final ChangedAttribute changedAttribute )
{
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
switch( changedAttribute )
{
case CHANNEL_STATE:
mStateLabel.setText( mState.getState().getDisplayValue() );
break;
case CHANNEL_SITE_NUMBER:
mSite.setText( String.valueOf( mState.getSite() ) );
Alias siteAlias = getSiteAlias( mState.getSite() );
if( siteAlias != null )
{
mSiteAliasLabel.setText( siteAlias.getName() );
}
repaint();
break;
case FROM_TALKGROUP:
mTalkgroup.setText( mState.getFromTalkgroup() );
Alias alias = getTalkgroupAlias( mState.getFromTalkgroup() );
if( alias != null )
{
mTalkgroupAlias.setText( alias.getName() );
mTalkgroupAlias.setIcon( getIcon( alias ) );
}
repaint();
break;
}
}
} );
}
private ImageIcon getIcon( Alias alias )
{
if( alias != null )
{
String iconName = alias.getIconName();
if( iconName != null )
{
return getSettingsManager().getImageIcon( iconName, 12 );
}
}
return null;
}
private Alias getSiteAlias( int site )
{
if( site != 0 && mAliasList != null )
{
return mAliasList.getSiteID( site );
}
return null;
}
private Alias getTalkgroupAlias( String talkgroup )
{
if( talkgroup != null && mAliasList != null )
{
return mAliasList.getTalkgroupAlias( talkgroup );
}
return null;
}
@Override
public void trafficChannelAdded( Channel traffic )
{
if( !getTrafficPanels().keySet().contains( traffic ) )
{
MPT1327TrafficPanel panel =
new MPT1327TrafficPanel( traffic );
getTrafficPanels().put( traffic, panel );
addPanel( panel );
}
}
@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( mProtocol != null )
{
mProtocol.setForeground( mColorLabelDecoder );
}
if( mStateLabel != null )
{
mStateLabel.setForeground( mColorLabelDecoder );
}
if( mTalkgroup != null )
{
mTalkgroup.setForeground( mColorLabelDecoder );
}
if( mTalkgroupAlias != null )
{
mTalkgroupAlias.setForeground( mColorLabelDecoder );
}
if( mSite != null )
{
mSite.setForeground( mColorLabelDecoder );
}
if( mSiteAliasLabel != null )
{
mSiteAliasLabel.setForeground( mColorLabelDecoder );
}
break;
case CHANNEL_STATE_LABEL_DETAILS:
if( mSourceLabel != null )
{
mSourceLabel.setForeground( mColorLabelDetails );
}
if( mChannelLabel != null )
{
mChannelLabel.setForeground( mColorLabelDetails );
}
if( mSiteLabel != null )
{
mSiteLabel.setForeground( mColorLabelDetails );
}
break;
}
}
}
}

View File

@@ -0,0 +1,258 @@
/*******************************************************************************
* 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.mpt1327;
import java.awt.EventQueue;
import javax.swing.JLabel;
import settings.ColorSetting;
import settings.Setting;
import alias.Alias;
import alias.AliasList;
import controller.channel.Channel;
import controller.channel.ProcessingChain;
import controller.state.ChannelState.ChangedAttribute;
import controller.state.ChannelStatePanel;
public class MPT1327TrafficPanel extends ChannelStatePanel
{
private static final long serialVersionUID = 1L;
private JLabel mProtocolLabel;
private JLabel mFrequencyLabel;
private JLabel mChannelLabel;
private JLabel mStateLabel;
private JLabel mFromTalkgroupLabel;
private JLabel mFromTalkgroupAliasLabel;
private JLabel mToLabel;
private JLabel mToTalkgroupLabel;
private JLabel mToTalkgroupAliasLabel;
private AliasList mAliasList;
public MPT1327TrafficPanel( Channel channel )
{
super( channel );
mAliasList = channel.getProcessingChain().getChannelState().getAliasList();
init();
}
public void dispose()
{
super.dispose();
mAliasList = null;
}
public void init()
{
mProtocolLabel = new JLabel( "MPT1327" );
mProtocolLabel.setFont( mFontDecoder );
mProtocolLabel.setForeground( mColorLabelDecoder );
mFrequencyLabel = new JLabel( mChannel.getSourceConfiguration().getDescription() );
mFrequencyLabel.setFont( mFontDetails );
mFrequencyLabel.setForeground( mColorLabelDetails );
MPT1327ChannelState state =
(MPT1327ChannelState)mChannel.getProcessingChain().getChannelState();
int channelNumber = state.getChannelNumber();
mChannelLabel = new JLabel( "Channel " + channelNumber );
mChannelLabel.setFont( mFontDetails );
mChannelLabel.setForeground( mColorLabelDetails );
mStateLabel = new JLabel( mChannel.getProcessingChain().
getChannelState().getState().getDisplayValue() );
mStateLabel.setFont( mFontDecoder );
mStateLabel.setForeground( mColorLabelDecoder );
mFromTalkgroupLabel = new JLabel( state.getFromTalkgroup() );
mFromTalkgroupLabel.setFont( mFontDecoder );
mFromTalkgroupLabel.setForeground( mColorLabelDecoder );
mFromTalkgroupAliasLabel = new JLabel();
mFromTalkgroupAliasLabel.setFont( mFontDecoder );
mFromTalkgroupAliasLabel.setForeground( mColorLabelDecoder );
if( mAliasList != null )
{
Alias alias = mAliasList.getMPT1327Alias( state.getFromTalkgroup() );
if( alias != null )
{
mFromTalkgroupAliasLabel.setText( alias.getName() );
mFromTalkgroupAliasLabel.setIcon( getChannel()
.getResourceManager().getSettingsManager()
.getImageIcon( alias.getIconName(), 12 ) );
}
}
mToLabel = new JLabel( "TO:" );
mToLabel.setFont( mFontDetails );
mToLabel.setForeground( mColorLabelDetails );
mToTalkgroupLabel = new JLabel( state.getFromTalkgroup() );
mToTalkgroupLabel.setFont( mFontDecoder );
mToTalkgroupLabel.setForeground( mColorLabelDecoder );
mToTalkgroupAliasLabel = new JLabel();
mToTalkgroupAliasLabel.setFont( mFontDecoder );
mToTalkgroupAliasLabel.setForeground( mColorLabelDecoder );
if( mAliasList != null )
{
Alias alias = mAliasList.getMPT1327Alias( state.getFromTalkgroup() );
if( alias != null )
{
mToTalkgroupAliasLabel.setText( alias.getName() );
mToTalkgroupAliasLabel.setIcon( getChannel()
.getResourceManager().getSettingsManager()
.getImageIcon( alias.getIconName(), 12 ) );
}
}
add( mProtocolLabel );
add( mFrequencyLabel );
add( mChannelLabel, "wrap" );
add( mStateLabel );
add( mFromTalkgroupLabel );
add( mFromTalkgroupAliasLabel, "wrap" );
add( mToLabel );
add( mToTalkgroupLabel );
add( mToTalkgroupAliasLabel, "wrap" );
}
@Override
public void receive( final ChangedAttribute changedAttribute )
{
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
ProcessingChain chain = getChannel().getProcessingChain();
if( chain != null )
{
final MPT1327ChannelState state =
(MPT1327ChannelState)chain.getChannelState();
if( state != null )
{
switch( changedAttribute )
{
case CHANNEL_STATE:
mStateLabel.setText( state.getState().getDisplayValue() );
break;
case CHANNEL_NUMBER:
mChannelLabel.setText( "Channel " + state.getChannelNumber() );
break;
case FROM_TALKGROUP:
String talkgroup = state.getFromTalkgroup();
mFromTalkgroupLabel.setText( talkgroup );
if( mAliasList != null )
{
Alias alias = mAliasList.getMPT1327Alias( talkgroup );
if( alias != null )
{
mFromTalkgroupAliasLabel.setText( alias.getName() );
String icon = alias.getIconName();
mFromTalkgroupAliasLabel.setIcon( getChannel()
.getResourceManager().getSettingsManager()
.getImageIcon( icon, 12 ) );
}
}
break;
case TO_TALKGROUP:
String toTalkgroup = state.getToTalkgroup();
mToTalkgroupLabel.setText( toTalkgroup );
if( mAliasList != null )
{
Alias alias = mAliasList.getMPT1327Alias( toTalkgroup );
if( alias != null )
{
mToTalkgroupAliasLabel.setText( alias.getName() );
String icon = alias.getIconName();
if( icon != null )
{
mToTalkgroupAliasLabel.setIcon( getChannel()
.getResourceManager().getSettingsManager()
.getImageIcon( icon, 12 ) );
}
}
}
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:
mProtocolLabel.setForeground( mColorLabelDecoder );
mStateLabel.setForeground( mColorLabelDecoder );
mFromTalkgroupLabel.setForeground( mColorLabelDecoder );
mFromTalkgroupAliasLabel.setForeground( mColorLabelDecoder );
mToTalkgroupLabel.setForeground( mColorLabelDecoder );
mToTalkgroupAliasLabel.setForeground( mColorLabelDecoder );
break;
case CHANNEL_STATE_LABEL_DETAILS:
mFrequencyLabel.setForeground( mColorLabelDetails );
mChannelLabel.setForeground( mColorLabelDetails );
mToLabel.setForeground( mColorLabelDetails );
break;
}
}
}
}