Initial commit of redesigned internal processing and audio management.

Note: Several of the decoders are currently non-functioning in this
commit.  If you want the latest functioning codebase, please checkout
the commit prior to this one.  All decoders will eventually be updated
with this new architecture.

Currently broken:
- Logging and recording
- Aux decoders (Fleetsync/MDC/LoJack/Tait)
- LTR/Passport decoders

Changes in this commit:
- Module architecture for decoders and components with central
provisioning by the DecoderFactory
- Transition from Complex sample stream processing to float buffer
processing for improved memory management
- Redesigned filter structures - to support buffers and streams
- Resolved several memory leak issues
- Universal sharing of the thread pool manager
- Added centralized audio management with call/user prioritization and
new gui with mute/volume controls
- Embedded audio metadata for eventual streaming support
- Redesigned ProcessingChain to support independent re-use
- Added new TrafficChannelManager to handle traffic channel allocations
- Traffic Channel pool size and Call timeout available in P25 and
MPT1327 configs
- Redesigned channel and decoder gui components
This commit is contained in:
denny
2015-09-01 07:10:26 -04:00
parent 538a299246
commit f4d8ea281d
570 changed files with 21578 additions and 17012 deletions

View File

@@ -0,0 +1,102 @@
/*******************************************************************************
* 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 module.decode.mpt1327;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import module.decode.DecoderType;
import module.decode.config.DecodeConfiguration;
import module.decode.mpt1327.MPT1327Decoder.Sync;
public class DecodeConfigMPT1327 extends DecodeConfiguration
{
private String mChannelMapName;
private Sync mSync = Sync.NORMAL;
private int mCallTimeout = DEFAULT_CALL_TIMEOUT_SECONDS;
private int mTrafficChannelPoolSize = TRAFFIC_CHANNEL_LIMIT_DEFAULT;
public DecodeConfigMPT1327()
{
super( DecoderType.MPT1327 );
}
@XmlElement
public String getChannelMapName()
{
return mChannelMapName;
}
public void setChannelMapName( String name )
{
mChannelMapName = name;
}
@XmlAttribute( name="sync" )
public Sync getSync()
{
return mSync;
}
public void setSync( Sync sync )
{
mSync = sync;
}
@XmlAttribute( name="call_timeout" )
public int getCallTimeout()
{
return mCallTimeout;
}
/**
* Sets the call timeout value in seconds ( 10 - 600 );
* @param timeout
*/
public void setCallTimeout( int timeout )
{
if( CALL_TIMEOUT_MINIMUM <= timeout && timeout <= CALL_TIMEOUT_MAXIMUM )
{
mCallTimeout = timeout;
}
else
{
mCallTimeout = DEFAULT_CALL_TIMEOUT_SECONDS;
}
}
@XmlAttribute( name="traffic_channel_pool_size" )
public int getTrafficChannelPoolSize()
{
return mTrafficChannelPoolSize;
}
/**
* Sets the traffic channel pool size which is the maximum number of
* simultaneous traffic channels that can be allocated.
*
* This limits the maximum calls so that busy systems won't cause more
* traffic channels to be allocated than the decoder/software/host computer
* can support.
*/
public void setTrafficChannelPoolSize( int size )
{
mTrafficChannelPoolSize = size;
}
}

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 module.decode.mpt1327;
import module.decode.DecoderType;
import module.decode.event.CallEvent;
import alias.Alias;
import alias.AliasList;
public class MPT1327CallEvent extends CallEvent
{
private String mChannel;
private long mFrequency;
public MPT1327CallEvent( CallEventType callEventType,
AliasList aliasList,
String fromID,
String toID,
String channel,
long 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 String getChannel()
{
return mChannel;
}
@Override
public long 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 String mChannel;
private long 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( String channel )
{
mChannel = channel;
return this;
}
public Builder details( String details )
{
mDetails = details;
return this;
}
public Builder frequency( long frequency )
{
mFrequency = frequency;
return this;
}
public Builder to( String toID )
{
mToID = toID;
return this;
}
public 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,195 @@
/*******************************************************************************
* 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 module.decode.mpt1327;
import java.util.ArrayList;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import module.decode.DecodeEditor;
import module.decode.config.DecodeConfiguration;
import module.decode.mpt1327.MPT1327Decoder.Sync;
import controller.channel.ChannelNode;
import controller.channel.map.ChannelMap;
public class MPT1327ConfigEditor extends DecodeEditor
{
private static final long serialVersionUID = 1L;
private JComboBox<ChannelMap> mComboChannelMaps;
private JComboBox<Sync> mComboSync;
private JLabel mCallTimeoutLabel;
private JSlider mCallTimeout;
private JLabel mTrafficChannelPoolSizeLabel;
private JSlider mTrafficChannelPoolSize;
private ChannelNode mChannelNode;
public MPT1327ConfigEditor( DecodeConfiguration config, ChannelNode channelNode )
{
super( config );
mChannelNode = channelNode;
initGUI();
}
private DecodeConfigMPT1327 getMPTConfig()
{
return (DecodeConfigMPT1327)mConfig;
}
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:" ) );
add( mComboChannelMaps, "wrap" );
mComboSync = new JComboBox<Sync>();
mComboSync.setModel( new DefaultComboBoxModel<Sync>( Sync.values() ) );
add( new JLabel( "Sync:" ) );
add( mComboSync, "wrap" );
mCallTimeout = new JSlider( JSlider.HORIZONTAL,
DecodeConfiguration.CALL_TIMEOUT_MINIMUM,
DecodeConfiguration.CALL_TIMEOUT_MAXIMUM,
DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS );
mCallTimeout.setMajorTickSpacing( 90 );
mCallTimeout.setMinorTickSpacing( 10 );
mCallTimeout.setPaintTicks( true );
mCallTimeout.setLabelTable( mCallTimeout.createStandardLabels( 100, 100 ) );
mCallTimeout.setPaintLabels( true );
mCallTimeoutLabel = new JLabel( "Call Timeout: " + mCallTimeout.getValue() + " " );
mCallTimeout.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mCallTimeoutLabel.setText( "Call Timeout: " + mCallTimeout.getValue() );
}
} );
add( mCallTimeoutLabel );
add( mCallTimeout, "wrap,grow" );
mTrafficChannelPoolSize = new JSlider( JSlider.HORIZONTAL,
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MINIMUM,
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MAXIMUM,
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT );
mTrafficChannelPoolSize.setMajorTickSpacing( 10 );
mTrafficChannelPoolSize.setMinorTickSpacing( 1 );
mTrafficChannelPoolSize.setPaintTicks( true );
mTrafficChannelPoolSize.setLabelTable( mTrafficChannelPoolSize.createStandardLabels( 10, 10 ) );
mTrafficChannelPoolSize.setPaintLabels( true );
mTrafficChannelPoolSizeLabel = new JLabel( "Traffic Channel Pool Size: " + mTrafficChannelPoolSize.getValue() + " " );
mTrafficChannelPoolSize.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mTrafficChannelPoolSizeLabel.setText( "Traffic Channel Pool Size: " + mTrafficChannelPoolSize.getValue() );
}
} );
add( mTrafficChannelPoolSizeLabel );
add( mTrafficChannelPoolSize, "wrap,grow" );
reset();
}
@Override
public void save()
{
DecodeConfigMPT1327 config = getMPTConfig();
ChannelMap selected = (ChannelMap)mComboChannelMaps.getSelectedItem();
if( selected != null )
{
config.setChannelMapName( selected.getName() );
}
Sync selectedSync = (Sync)mComboSync.getSelectedItem();
if( selectedSync != null )
{
config.setSync( selectedSync );
}
config.setCallTimeout( mCallTimeout.getValue() );
config.setTrafficChannelPoolSize( mTrafficChannelPoolSize.getValue() );
}
@Override
public void reset()
{
DecodeConfigMPT1327 config = (DecodeConfigMPT1327)mConfig;
String name = config.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();
mComboSync.setSelectedItem( config.getSync() );
mCallTimeout.setValue( config.getCallTimeout() );
mTrafficChannelPoolSize.setValue( config.getTrafficChannelPoolSize() );
}
}

View File

@@ -0,0 +1,295 @@
/*******************************************************************************
* 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 module.decode.mpt1327;
import instrument.Instrumentable;
import instrument.tap.Tap;
import instrument.tap.stream.BinaryTap;
import instrument.tap.stream.FloatBufferTap;
import instrument.tap.stream.FloatTap;
import java.util.ArrayList;
import java.util.List;
import module.decode.Decoder;
import module.decode.DecoderType;
import sample.Broadcaster;
import sample.Listener;
import sample.real.IRealBufferListener;
import sample.real.RealBuffer;
import alias.AliasList;
import bits.MessageFramer;
import bits.SyncPattern;
import controller.channel.Channel.ChannelType;
import controller.channel.map.ChannelMap;
import dsp.filter.FilterFactory;
import dsp.filter.Filters;
import dsp.filter.Window.WindowType;
import dsp.filter.dc.DCRemovalFilterLyons;
import dsp.filter.fir.real.RealFIRFilter_RB_RB;
import dsp.filter.halfband.real.HalfBandFilter_RB_RB;
import dsp.fsk.FSK2Decoder;
import dsp.fsk.FSK2Decoder.Output;
/**
* 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 IRealBufferListener, Instrumentable
{
/* 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_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 HalfBandFilter_RB_RB mDecimationFilter;
private RealFIRFilter_RB_RB mLowPassFilter;
private DCRemovalFilterLyons mDCRemovalFilter;
private FSK2Decoder mFSKDecoder;
private Broadcaster<Boolean> mSymbolBroadcaster;
private MessageFramer mControlMessageFramer;
private MessageFramer mTrafficMessageFramer;
private MPT1327MessageProcessor mMessageProcessor;
public MPT1327Decoder( ChannelMap channelMap,
ChannelType channelType,
AliasList aliasList,
Sync sync )
{
super( new MPT1327DecoderState( aliasList, channelMap, channelType ) );
/* Decimation filter - 48000 / 2 = 24000 output */
mDecimationFilter = new HalfBandFilter_RB_RB(
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0002f, true );
/* Low pass filter: 2kHz to pass the 1200 & 1800 Hz FSK */
mLowPassFilter = new RealFIRFilter_RB_RB(
FilterFactory.getLowPass( 24000, //sampleRate,
2000, //passFrequency,
4000, //stopFrequency,
60, //attenuation,
WindowType.HANNING, //windowType,
true ) //forceOddLength
, 2.0f ); //Gain
mDecimationFilter.setListener( mLowPassFilter );
/**
* Normal: 2FSK Decoder with inverted output
* French: 2FSK Decoder with normal output
*/
if( sync == Sync.NORMAL )
{
mFSKDecoder = new FSK2Decoder( 24000, 1200, Output.INVERTED );
}
else if( sync == Sync.FRENCH )
{
mFSKDecoder = new FSK2Decoder( 24000, 1200, Output.NORMAL );
}
else
{
throw new IllegalArgumentException( "MPT1327 Decoder - unrecognized Sync type" );
}
mLowPassFilter.setListener( mFSKDecoder );
mSymbolBroadcaster = new Broadcaster<Boolean>();
mFSKDecoder.setListener( mSymbolBroadcaster );
/* Message framer for control channel messages */
mControlMessageFramer =
new MessageFramer( sync.getControlSyncPattern().getPattern(),
sMESSAGE_LENGTH );
mSymbolBroadcaster.addListener( mControlMessageFramer );
/* Message framer for traffic channel massages */
mTrafficMessageFramer =
new MessageFramer( sync.getTrafficSyncPattern().getPattern(),
sMESSAGE_LENGTH );
mSymbolBroadcaster.addListener( mTrafficMessageFramer );
/* Fully decoded and framed messages processor */
mMessageProcessor = new MPT1327MessageProcessor( aliasList );
mMessageProcessor.setMessageListener( mMessageBroadcaster );
mControlMessageFramer.addMessageListener( mMessageProcessor );
mTrafficMessageFramer.addMessageListener( mMessageProcessor );
}
@Override
public Listener<RealBuffer> getRealBufferListener()
{
return mDecimationFilter;
}
@Override
public DecoderType getDecoderType()
{
return DecoderType.MPT1327;
}
/**
* Cleanup method
*/
public void dispose()
{
super.dispose();
mSymbolBroadcaster.dispose();
mControlMessageFramer.dispose();
if( mDCRemovalFilter != null )
{
mDCRemovalFilter.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_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_HB1_FILTER_TO_LOW_PASS:
FloatBufferTap hb1Tap = (FloatBufferTap)tap;
mDecimationFilter.setListener( hb1Tap );
hb1Tap.setListener( mLowPassFilter );
break;
case INSTRUMENT_LOW_PASS_TO_DECODER:
FloatBufferTap lowTap = (FloatBufferTap)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_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;
}
}
public enum Sync
{
NORMAL( "Normal",
SyncPattern.MPT1327_CONTROL,
SyncPattern.MPT1327_TRAFFIC ),
FRENCH( "French",
SyncPattern.MPT1327_CONTROL_FRENCH,
SyncPattern.MPT1327_TRAFFIC_FRENCH );
private String mLabel;
private SyncPattern mControlSyncPattern;
private SyncPattern mTrafficSyncPattern;
private Sync( String label,
SyncPattern controlPattern,
SyncPattern trafficPattern )
{
mLabel = label;
mControlSyncPattern = controlPattern;
mTrafficSyncPattern = trafficPattern;
}
public String getLabel()
{
return mLabel;
}
public SyncPattern getControlSyncPattern()
{
return mControlSyncPattern;
}
public SyncPattern getTrafficSyncPattern()
{
return mTrafficSyncPattern;
}
public String toString()
{
return getLabel();
}
}
}

View File

@@ -0,0 +1,222 @@
/*******************************************************************************
* 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 module.decode.mpt1327;
import java.awt.EventQueue;
import javax.swing.JLabel;
import module.decode.state.ChangedAttribute;
import module.decode.state.DecoderPanel;
import net.miginfocom.swing.MigLayout;
import settings.ColorSetting;
import settings.Setting;
import settings.SettingsManager;
import alias.Alias;
import controller.channel.Channel.ChannelType;
public class MPT1327DecoderPanel extends DecoderPanel
{
private static final long serialVersionUID = 1L;
private JLabel mProtocol = new JLabel( "" );
private JLabel mSiteOrFromTalkgroup = new JLabel( "" );
private JLabel mSiteOrFromTalkgroupAlias = new JLabel( "" );
private JLabel mToTalkgroupLabel = new JLabel( "" );
private JLabel mToTalkgroup = new JLabel( "" );
private JLabel mToTalkgroupAliasLabel = new JLabel( "" );
public MPT1327DecoderPanel( SettingsManager settingsManager, MPT1327Decoder decoder )
{
super( settingsManager, decoder );
init();
}
private MPT1327DecoderState getDecoderState()
{
return (MPT1327DecoderState)getDecoder().getDecoderState();
}
public void dispose()
{
super.dispose();
}
public void init()
{
super.init();
setLayout( new MigLayout( "insets 0 0 0 0", "[grow,fill]", "[]0[]0[]") );
mProtocol.setText( "MPT1327" );
mProtocol.setFont( mFontDecoder );
mProtocol.setForeground( mColorLabelDecoder );
MPT1327DecoderState mptState = getDecoderState();
mSiteOrFromTalkgroup.setFont( mFontDecoder );
mSiteOrFromTalkgroup.setForeground( mColorLabelDecoder );
mSiteOrFromTalkgroupAlias.setFont( mFontDecoder );
mSiteOrFromTalkgroupAlias.setForeground( mColorLabelDecoder );
mToTalkgroupLabel.setFont( mFontDetails );
mToTalkgroupLabel.setForeground( mColorLabelDetails );
mToTalkgroup.setFont( mFontDecoder );
mToTalkgroup.setForeground( mColorLabelDecoder );
mToTalkgroupAliasLabel.setFont( mFontDecoder );
mToTalkgroupAliasLabel.setForeground( mColorLabelDecoder );
switch( mptState.getChannelType() )
{
case STANDARD:
mSiteOrFromTalkgroup.setText( mptState.getSite() );
setAliasLabel( mSiteOrFromTalkgroupAlias, mptState.getSiteAlias() );
break;
case TRAFFIC:
mSiteOrFromTalkgroup.setText( mptState.getFromTalkgroup() );
setAliasLabel( mSiteOrFromTalkgroupAlias, mptState.getFromTalkgroupAlias() );
mToTalkgroupLabel.setText( "To:" );
mToTalkgroup.setText( getDecoderState().getToTalkgroup() );
setAliasLabel( mToTalkgroupAliasLabel, mptState.getToTalkgroupAlias() );
break;
default:
throw new IllegalArgumentException( "Unrecognized channel "
+ "type in MPT1327 Decoder [" + getDecoderState()
.getChannelType().name() + "]" );
}
add( mProtocol );
add( mSiteOrFromTalkgroup );
add( mSiteOrFromTalkgroupAlias, "wrap" );
if( mptState.getChannelType() == ChannelType.TRAFFIC )
{
add( mToTalkgroupLabel );
add( mToTalkgroup );
add( mToTalkgroupAliasLabel, "wrap" );
}
}
private void setAliasLabel( final JLabel label, final Alias alias )
{
if( alias != null )
{
label.setText( alias.getName() );
String iconName = alias.getIconName();
if( iconName != null )
{
label.setIcon( mSettingsManager.getImageIcon( iconName, 12 ) );
}
else
{
label.setIcon( null );
}
}
else
{
label.setText( "" );
label.setIcon( null );
}
}
@Override
public void receive( final ChangedAttribute changedAttribute )
{
final MPT1327DecoderState state = getDecoderState();
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
switch( changedAttribute )
{
case CHANNEL_SITE_NUMBER:
mSiteOrFromTalkgroup.setText( String.valueOf( state.getSite() ) );
setAliasLabel( mSiteOrFromTalkgroupAlias, state.getSiteAlias() );
repaint();
break;
case FROM_TALKGROUP:
mSiteOrFromTalkgroup.setText( state.getFromTalkgroup() );
setAliasLabel( mSiteOrFromTalkgroupAlias, state.getFromTalkgroupAlias() );
repaint();
break;
case TO_TALKGROUP:
mToTalkgroup.setText( state.getToTalkgroup() );
setAliasLabel( mToTalkgroupAliasLabel, state.getToTalkgroupAlias() );
repaint();
break;
default:
break;
}
}
} );
}
@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( mSiteOrFromTalkgroup != null )
{
mSiteOrFromTalkgroup.setForeground( mColorLabelDecoder );
}
if( mSiteOrFromTalkgroupAlias != null )
{
mSiteOrFromTalkgroupAlias.setForeground( mColorLabelDecoder );
}
if( mToTalkgroup != null )
{
mToTalkgroup.setForeground( mColorLabelDecoder );
}
if( mToTalkgroupAliasLabel != null )
{
mToTalkgroupAliasLabel.setForeground( mColorLabelDecoder );
}
break;
case CHANNEL_STATE_LABEL_DETAILS:
if( mToTalkgroupLabel != null )
{
mToTalkgroupLabel.setForeground( mColorLabelDetails );
}
break;
}
}
}
}

View File

@@ -0,0 +1,572 @@
/*******************************************************************************
* 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 module.decode.mpt1327;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
import message.Message;
import module.decode.event.CallEvent;
import module.decode.event.CallEvent.CallEventType;
import module.decode.mpt1327.MPT1327Message.IdentType;
import module.decode.state.ChangedAttribute;
import module.decode.state.DecoderState;
import module.decode.state.DecoderStateEvent;
import module.decode.state.DecoderStateEvent.Event;
import module.decode.state.State;
import module.decode.state.TrafficChannelAllocationEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import alias.Alias;
import alias.AliasList;
import controller.channel.Channel.ChannelType;
import controller.channel.map.ChannelMap;
public class MPT1327DecoderState extends DecoderState
{
private final static Logger mLog = LoggerFactory.getLogger( MPT1327DecoderState.class );
private TreeSet<String> mIdents = new TreeSet<String>();
private HashMap<String,ArrayList<String>> mGroups = new HashMap<String,ArrayList<String>>();
private String mSite;
private String mFromTalkgroup;
private String mToTalkgroup;
private int mChannelNumber;
private ChannelType mChannelType;
private ChannelMap mChannelMap;
private long mFrequency = 0;
public MPT1327DecoderState( AliasList aliasList, ChannelMap channelMap,
ChannelType channelType )
{
super( aliasList );
mChannelMap = channelMap;
mChannelType = channelType;
}
public ChannelType getChannelType()
{
return mChannelType;
}
public void dispose()
{
super.dispose();
}
@Override
public void receive( Message message )
{
if( message.isValid() )
{
if( message instanceof MPT1327Message )
{
MPT1327Message mpt = ((MPT1327Message)message);
switch( mpt.getMessageType() )
{
case ACK:
mIdents.add( mpt.getFromID() );
IdentType identType = mpt.getIdent1Type();
if( identType == IdentType.REGI )
{
broadcast( new MPT1327CallEvent.Builder( CallEventType.REGISTER )
.aliasList( getAliasList() )
.channel( String.valueOf( mChannelNumber ) )
.details( "REGISTERED ON NETWORK" )
.frequency( mFrequency )
.from( mpt.getToID() )
.to( mpt.getFromID() )
.build() );
}
else
{
broadcast( new MPT1327CallEvent.Builder( CallEventType.RESPONSE )
.aliasList( getAliasList() )
.channel( String.valueOf( mChannelNumber ) )
.details( "ACK " + identType.getLabel() )
.frequency( mFrequency )
.from( mpt.getFromID() )
.to( mpt.getToID() )
.build() );
}
broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CONTROL ) );
break;
case ACKI:
mIdents.add( mpt.getFromID() );
mIdents.add( mpt.getToID() );
broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CONTROL ) );
break;
case AHYC:
mIdents.add( mpt.getToID() );
broadcast( new MPT1327CallEvent.Builder( CallEventType.COMMAND )
.aliasList( getAliasList() )
.channel( String.valueOf( mChannelNumber ) )
.details( ( (MPT1327Message) message ).getRequestString() )
.frequency( mFrequency )
.from( mpt.getFromID() )
.to( mpt.getToID() )
.build() );
broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CONTROL ) );
break;
case AHYQ:
broadcast( new MPT1327CallEvent.Builder( CallEventType.STATUS )
.aliasList( getAliasList() )
.channel( String.valueOf( mChannelNumber ) )
.details( mpt.getStatusMessage() )
.frequency( mFrequency )
.from( mpt.getFromID() )
.to( mpt.getToID() )
.build() );
broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CONTROL ) );
break;
case ALH:
String site = mpt.getSiteID();
if( site != null && ( mSite == null || !site.contentEquals( mSite ) ) )
{
mSite = site;
broadcast( ChangedAttribute.CHANNEL_SITE_NUMBER );
}
mSite = mpt.getSiteID();
broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CONTROL ) );
break;
case GTC:
String from = mpt.getFromID();
String to = mpt.getToID();
if( from != null )
{
mIdents.add( from );
}
if( to != null )
{
mIdents.add( to );
}
/* Capture the idents that talk to each group */
if( from != null && to != null )
{
if( mGroups.containsKey( to ) )
{
ArrayList<String> talkgroups = mGroups.get( to );
if( !talkgroups.contains( from ) )
{
talkgroups.add( from );
}
}
else
{
ArrayList<String> talkgroups = new ArrayList<String>();
talkgroups.add( from );
mGroups.put( to, talkgroups );
}
}
int channel = mpt.getChannel();
long frequency = 0;
if( getChannelMap() != null )
{
frequency = getChannelMap().getFrequency( channel );
}
CallEvent event = new MPT1327CallEvent.Builder( CallEventType.CALL )
.aliasList( getAliasList() )
.channel( String.valueOf( channel ) )
.details( "GTC" )
.frequency( frequency )
.from( mpt.getFromID() )
.to( mpt.getToID() )
.build();
broadcast( new TrafficChannelAllocationEvent( this, event ) );
break;
case HEAD_PLUS1:
case HEAD_PLUS2:
case HEAD_PLUS3:
case HEAD_PLUS4:
broadcast( new MPT1327CallEvent.Builder( CallEventType.SDM )
.aliasList( getAliasList() )
.details( mpt.getMessage() )
.from( mpt.getFromID() )
.to( mpt.getToID() )
.build() );
broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CONTROL ) );
break;
/* Traffic Channel Events */
case CLEAR:
case MAINT:
broadcast( new DecoderStateEvent( this, Event.END, State.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 ) )
// {
// CallEvent current = getCurrentCallEvent();
//
// if( current != null )
// {
// mCallEventModel.setEnd( current );
// }
// else
// {
// mCallEventModel.add(
// new MPT1327CallEvent.Builder( type )
// .aliasList( getAliasList() )
// .channel( String.valueOf( mChannelNumber ) )
// .frequency( mChannelMap.getFrequency( mChannelNumber ) )
// .from( mFromTalkgroup )
// .to( mToTalkgroup )
// .build() );
// }
//
// setCurrentCall( null );
// }
//
// super.fade( type );
// }
public void reset()
{
mIdents.clear();
resetState();
}
private void resetState()
{
mFromTalkgroup = null;
broadcast( ChangedAttribute.FROM_TALKGROUP );
mToTalkgroup = null;
broadcast( ChangedAttribute.TO_TALKGROUP );
}
public String getSite()
{
return mSite;
}
public Alias getSiteAlias()
{
if( hasAliasList() )
{
return getAliasList().getSiteID( mSite );
}
return null;
}
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;
broadcast( ChangedAttribute.FROM_TALKGROUP );
}
public Alias getFromTalkgroupAlias()
{
if( hasAliasList() )
{
return getAliasList().getTalkgroupAlias( mFromTalkgroup );
}
return null;
}
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;
broadcast( ChangedAttribute.TO_TALKGROUP );
}
public Alias getToTalkgroupAlias()
{
if( hasAliasList() )
{
return getAliasList().getTalkgroupAlias( mToTalkgroup );
}
return null;
}
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;
broadcast( ChangedAttribute.CHANNEL_NUMBER );
}
@Override
public String getActivitySummary()
{
StringBuilder sb = new StringBuilder();
sb.append( "Activity Summary\n" );
sb.append( "Decoder:\tMPT-1327\n" );
sb.append( "Site:\t" );
if( mSite != null )
{
sb.append( mSite );
if( hasAliasList() )
{
Alias siteAlias = getAliasList().getSiteID( mSite );
if( siteAlias != null )
{
sb.append( " " );
sb.append( siteAlias.getName() );
sb.append( "\n" );
}
}
}
else
{
sb.append( "Unknown\n" );
}
sb.append( "\n\n" );
sb.append( "Talkgroups\n\n" );
if( mGroups.isEmpty() )
{
sb.append( " None\n" );
}
else
{
List<String> talkgroups = new ArrayList<String>( mGroups.keySet() );
Collections.sort( talkgroups );
for( String talkgroup: talkgroups )
{
sb.append( " " );
sb.append( talkgroup );
if( hasAliasList() )
{
Alias alias = getAliasList().getMPT1327Alias( talkgroup );
if( alias != null )
{
sb.append( " " );
sb.append( alias.getName() );
}
}
sb.append( "\n" );
ArrayList<String> members = mGroups.get( talkgroup );
Collections.sort( members );
for( String member: members )
{
sb.append( " >" );
sb.append( member );
if( hasAliasList() )
{
Alias alias = getAliasList().getMPT1327Alias( member );
if( alias != null )
{
sb.append( " " );
sb.append( alias.getName() );
}
}
sb.append( "\n" );
}
sb.append( "\n" );
}
}
sb.append( "\n" );
sb.append( "Individual Idents\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( " " );
if( hasAliasList() )
{
Alias alias = getAliasList().getMPT1327Alias( ident );
if( alias != null )
{
sb.append( alias.getName() );
}
}
sb.append( "\n" );
}
}
return sb.toString();
}
@Override
public void init()
{
/* No initialization required */
}
@Override
public void receiveDecoderStateEvent( DecoderStateEvent event )
{
switch( event.getEvent() )
{
case RESET:
resetState();
break;
case SOURCE_FREQUENCY:
mFrequency = event.getFrequency();
break;
case TRAFFIC_CHANNEL_ALLOCATION:
if( event.getSource() != MPT1327DecoderState.this )
{
if( event instanceof TrafficChannelAllocationEvent )
{
TrafficChannelAllocationEvent allocationEvent =
(TrafficChannelAllocationEvent)event;
String channel = allocationEvent.getCallEvent().getChannel();
if( channel != null )
{
try
{
mChannelNumber = Integer.valueOf( channel );
broadcast( ChangedAttribute.CHANNEL_NUMBER );
}
catch( Exception e )
{
//Do nothing, we couldn't parse the channel number
}
}
mFrequency = allocationEvent.getCallEvent().getFrequency();
broadcast( ChangedAttribute.SOURCE );
mFromTalkgroup = allocationEvent.getCallEvent().getFromID();
broadcast( ChangedAttribute.FROM_TALKGROUP );
mToTalkgroup = allocationEvent.getCallEvent().getToID();
broadcast( ChangedAttribute.TO_TALKGROUP );
}
}
break;
default:
break;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
package module.decode.mpt1327;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import message.Message;
import module.decode.mpt1327.MPT1327Message.MPTMessageType;
import filter.Filter;
import filter.FilterElement;
public class MPT1327MessageFilter extends Filter<Message>
{
private HashMap<MPTMessageType,FilterElement<MPTMessageType>> mFilterElements =
new HashMap<MPTMessageType,FilterElement<MPTMessageType>>();
public MPT1327MessageFilter()
{
super( "MPT1327 Message Type Filter" );
for( MPTMessageType type: MPT1327Message.MPTMessageType.values() )
{
if( type != MPTMessageType.UNKN )
{
mFilterElements.put( type,
new FilterElement<MPTMessageType>( type ) );
}
}
}
@Override
public boolean passes( Message message )
{
if( mEnabled && canProcess( message ) )
{
MPT1327Message mpt = (MPT1327Message)message;
FilterElement<MPTMessageType> element =
mFilterElements.get( mpt.getMessageType() );
if( element != null )
{
return element.isEnabled();
}
}
return false;
}
@Override
public boolean canProcess( Message message )
{
return message instanceof MPT1327Message;
}
@Override
public List<FilterElement<?>> getFilterElements()
{
return new ArrayList<FilterElement<?>>( mFilterElements.values() );
}
}

View File

@@ -0,0 +1,67 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014,2015 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.mpt1327;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import message.Message;
import module.decode.DecoderFactory;
import sample.Listener;
import alias.AliasList;
import bits.BinaryMessage;
public class MPT1327MessageProcessor implements Listener<BinaryMessage>
{
private final static Logger mLog = LoggerFactory.getLogger( MPT1327MessageProcessor.class );
private Listener<Message> mMessageListener;
private AliasList mAliasList;
public MPT1327MessageProcessor( AliasList list )
{
mAliasList = list;
}
public void dispose()
{
mMessageListener = null;
}
@Override
public void receive( BinaryMessage buffer )
{
if( mMessageListener != null )
{
MPT1327Message message = new MPT1327Message( buffer, mAliasList );
mMessageListener.receive( message );
}
}
public void setMessageListener( Listener<Message> listener )
{
mMessageListener = listener;
}
public void removeMessageListener()
{
mMessageListener = null;
}
}

View File

@@ -0,0 +1,177 @@
/*******************************************************************************
* 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 module.decode.mpt1327;
import java.awt.EventQueue;
import javax.swing.JLabel;
import module.decode.state.ChangedAttribute;
import module.decode.state.DecoderPanel;
import settings.ColorSetting;
import settings.Setting;
import settings.SettingsManager;
import alias.Alias;
public class MPT1327TrafficPanel extends DecoderPanel
{
private static final long serialVersionUID = 1L;
private JLabel mProtocolLabel;
private JLabel mFromTalkgroupLabel;
private JLabel mFromTalkgroupAliasLabel;
private JLabel mToLabel;
private JLabel mToTalkgroupLabel;
private JLabel mToTalkgroupAliasLabel;
public MPT1327TrafficPanel( SettingsManager settingsManager, MPT1327Decoder decoder )
{
super( settingsManager, decoder );
init();
}
private MPT1327DecoderState getDecoderState()
{
return (MPT1327DecoderState)getDecoder().getDecoderState();
}
public void dispose()
{
super.dispose();
}
public void init()
{
mProtocolLabel = new JLabel( "MPT1327" );
mProtocolLabel.setFont( mFontDecoder );
mProtocolLabel.setForeground( mColorLabelDecoder );
mFromTalkgroupLabel = new JLabel();
mFromTalkgroupLabel.setFont( mFontDecoder );
mFromTalkgroupLabel.setForeground( mColorLabelDecoder );
mFromTalkgroupAliasLabel = new JLabel();
mFromTalkgroupAliasLabel.setFont( mFontDecoder );
mFromTalkgroupAliasLabel.setForeground( mColorLabelDecoder );
mToLabel = new JLabel( "TO:" );
mToLabel.setFont( mFontDetails );
mToLabel.setForeground( mColorLabelDetails );
mToTalkgroupLabel = new JLabel( getDecoderState().getFromTalkgroup() );
mToTalkgroupLabel.setFont( mFontDecoder );
mToTalkgroupLabel.setForeground( mColorLabelDecoder );
mToTalkgroupAliasLabel = new JLabel();
mToTalkgroupAliasLabel.setFont( mFontDecoder );
mToTalkgroupAliasLabel.setForeground( mColorLabelDecoder );
add( mProtocolLabel );
add( mFromTalkgroupLabel );
add( mFromTalkgroupAliasLabel, "wrap" );
add( mToLabel );
add( mToTalkgroupLabel );
add( mToTalkgroupAliasLabel, "wrap" );
}
@Override
public void receive( final ChangedAttribute changedAttribute )
{
final MPT1327DecoderState state = getDecoderState();
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
switch( changedAttribute )
{
case FROM_TALKGROUP:
String talkgroup = state.getFromTalkgroup();
mFromTalkgroupLabel.setText( talkgroup );
Alias alias = state.getFromTalkgroupAlias();
if( alias != null )
{
mFromTalkgroupAliasLabel.setText( alias.getName() );
String icon = alias.getIconName();
mFromTalkgroupAliasLabel.setIcon( mSettingsManager
.getImageIcon( icon, 12 ) );
}
break;
case TO_TALKGROUP:
String toTalkgroup = state.getToTalkgroup();
mToTalkgroupLabel.setText( toTalkgroup );
Alias toAlias = state.getToTalkgroupAlias();
if( toAlias != null )
{
mToTalkgroupAliasLabel.setText( toAlias.getName() );
String icon = toAlias.getIconName();
if( icon != null )
{
mToTalkgroupAliasLabel.setIcon( mSettingsManager
.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 );
mFromTalkgroupLabel.setForeground( mColorLabelDecoder );
mFromTalkgroupAliasLabel.setForeground( mColorLabelDecoder );
mToTalkgroupLabel.setForeground( mColorLabelDecoder );
mToTalkgroupAliasLabel.setForeground( mColorLabelDecoder );
break;
case CHANNEL_STATE_LABEL_DETAILS:
mToLabel.setForeground( mColorLabelDetails );
break;
}
}
}
}