mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
Closes #42 - ltr standard call state was not accurately tracking call
state. Note: a related issue described in ticket #42 involves issues with the audio output module. A new ticket will be opened with that issue.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,52 +17,94 @@
|
||||
******************************************************************************/
|
||||
package message;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import map.Plottable;
|
||||
import module.decode.event.MessageDetailsProvider;
|
||||
import alias.Alias;
|
||||
|
||||
public abstract class Message implements MessageDetailsProvider
|
||||
public abstract class Message
|
||||
{
|
||||
protected long mTimeReceived;
|
||||
protected MessageType mType;
|
||||
|
||||
public Message()
|
||||
{
|
||||
this( MessageType.UN_KNWN );
|
||||
}
|
||||
|
||||
public Message( MessageType type )
|
||||
{
|
||||
mTimeReceived = System.currentTimeMillis();
|
||||
mType = type;
|
||||
}
|
||||
|
||||
public abstract Plottable getPlottable();
|
||||
|
||||
public abstract String toString();
|
||||
|
||||
public abstract boolean isValid();
|
||||
|
||||
public long getTimeReceived()
|
||||
{
|
||||
return mTimeReceived;
|
||||
}
|
||||
|
||||
public Date getDateReceived()
|
||||
|
||||
/**
|
||||
* Map plottable
|
||||
*/
|
||||
public Plottable getPlottable()
|
||||
{
|
||||
return new Date( mTimeReceived );
|
||||
}
|
||||
|
||||
public MessageType getType()
|
||||
{
|
||||
return mType;
|
||||
//TODO: move this to an IPlottable interface that only gets implemented as needed
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decoded textual representation of the message
|
||||
*/
|
||||
public abstract String toString();
|
||||
|
||||
/**
|
||||
* Indicates if the message is valid and has passed crc/integrity checks
|
||||
*/
|
||||
public abstract boolean isValid();
|
||||
|
||||
/**
|
||||
* Status of the CRC check of the message
|
||||
*/
|
||||
public abstract String getErrorStatus();
|
||||
|
||||
/**
|
||||
* Parsed Message
|
||||
* @return
|
||||
*/
|
||||
public abstract String getMessage();
|
||||
|
||||
/**
|
||||
* Raw ( 0 & 1 ) message bits
|
||||
*/
|
||||
public abstract String getBinaryMessage();
|
||||
|
||||
|
||||
/**
|
||||
* Decoded protocol
|
||||
*/
|
||||
public abstract String getProtocol();
|
||||
|
||||
/**
|
||||
* Event - call, data, idle, etc.
|
||||
*/
|
||||
public abstract String getEventType();
|
||||
|
||||
/**
|
||||
* Formatted from identifier
|
||||
*/
|
||||
public abstract String getFromID();
|
||||
|
||||
/**
|
||||
* From identifier alias (from AliasManager)
|
||||
*/
|
||||
public abstract Alias getFromIDAlias();
|
||||
|
||||
/**
|
||||
* Formatted to identifier
|
||||
*/
|
||||
public abstract String getToID();
|
||||
|
||||
/**
|
||||
* To identifier alias (from AliasManager)
|
||||
* @return
|
||||
*/
|
||||
public abstract Alias getToIDAlias();
|
||||
|
||||
|
||||
/**
|
||||
* Provides a listing of aliases contained in the message.
|
||||
*/
|
||||
|
||||
@@ -19,6 +19,7 @@ package module.decode.event;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
@@ -174,7 +175,7 @@ public class MessageActivityModel extends AbstractTableModel
|
||||
switch( columnIndex )
|
||||
{
|
||||
case sTIME:
|
||||
return mSDFTime.format( message.getDateReceived() );
|
||||
return mSDFTime.format( new Date( message.getTimeReceived() ) );
|
||||
case sPROTOCOL:
|
||||
return message.getProtocol();
|
||||
case sERROR_STATUS:
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.event;
|
||||
|
||||
import alias.Alias;
|
||||
|
||||
/**
|
||||
* Getter methods to support the Message Activity Table/Model
|
||||
*/
|
||||
public interface MessageDetailsProvider
|
||||
{
|
||||
/**
|
||||
* Indicates if the message is valid and has passed crc/integrity checks
|
||||
*/
|
||||
public abstract boolean isValid();
|
||||
|
||||
/**
|
||||
* Status of the CRC check of the message
|
||||
*/
|
||||
public abstract String getErrorStatus();
|
||||
|
||||
/**
|
||||
* Parsed Message
|
||||
* @return
|
||||
*/
|
||||
public abstract String getMessage();
|
||||
|
||||
/**
|
||||
* Raw ( 0 & 1 ) message bits
|
||||
*/
|
||||
public abstract String getBinaryMessage();
|
||||
|
||||
|
||||
/**
|
||||
* Decoded protocol
|
||||
*/
|
||||
public abstract String getProtocol();
|
||||
|
||||
/**
|
||||
* Event - call, data, idle, etc.
|
||||
*/
|
||||
public abstract String getEventType();
|
||||
|
||||
/**
|
||||
* Formatted from identifier
|
||||
*/
|
||||
public abstract String getFromID();
|
||||
|
||||
/**
|
||||
* From identifier alias (from AliasManager)
|
||||
*/
|
||||
public abstract Alias getFromIDAlias();
|
||||
|
||||
/**
|
||||
* Formatted to identifier
|
||||
*/
|
||||
public abstract String getToID();
|
||||
|
||||
/**
|
||||
* To identifier alias (from AliasManager)
|
||||
* @return
|
||||
*/
|
||||
public abstract Alias getToIDAlias();
|
||||
|
||||
}
|
||||
@@ -51,17 +51,16 @@ public class LTRCallEvent extends CallEvent
|
||||
*/
|
||||
public boolean isMatchingTalkgroup( LTRNetMessage message )
|
||||
{
|
||||
String talkgroup = message.getTalkgroupID();
|
||||
|
||||
if( talkgroup != null && getToID() != null &&
|
||||
talkgroup.contentEquals( getToID() ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return isMatchingTalkgroup( message.getTalkgroupID() );
|
||||
}
|
||||
|
||||
public boolean isMatchingTalkgroup( String talkgroup )
|
||||
{
|
||||
return talkgroup != null &&
|
||||
getToID() != null &&
|
||||
talkgroup.contentEquals( getToID() );
|
||||
}
|
||||
|
||||
private Alias getAlias( String talkgroup )
|
||||
{
|
||||
if( hasAliasList() )
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014,2015 Dennis Sheirer
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,21 +17,31 @@
|
||||
******************************************************************************/
|
||||
package module.decode.ltrstandard;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import message.Message;
|
||||
import module.decode.DecoderType;
|
||||
import module.decode.event.CallEvent.CallEventType;
|
||||
import module.decode.ltrnet.LTRCallEvent;
|
||||
import module.decode.ltrstandard.message.CallEndMessage;
|
||||
import module.decode.ltrstandard.message.CallMessage;
|
||||
import module.decode.ltrstandard.message.IdleMessage;
|
||||
import module.decode.ltrstandard.message.LTRStandardMessage;
|
||||
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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import audio.metadata.Metadata;
|
||||
@@ -39,15 +49,17 @@ import audio.metadata.MetadataType;
|
||||
|
||||
public class LTRStandardDecoderState extends DecoderState
|
||||
{
|
||||
private HashMap<Integer,String> mActiveCalls = new HashMap<Integer,String>();
|
||||
private HashSet<String> mTalkgroupsFirstHeard = new HashSet<String>();
|
||||
private TreeSet<String> mTalkgroups = new TreeSet<String>();
|
||||
private TreeSet<Integer> mActiveLCNs = new TreeSet<Integer>();
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( LTRStandardDecoderState.class );
|
||||
|
||||
private Map<Integer,LTRCallEvent> mActiveCalls = new HashMap<>();
|
||||
private Set<String> mTalkgroupsFirstHeard = new HashSet<>();
|
||||
private Set<String> mTalkgroups = new TreeSet<>();
|
||||
|
||||
private String mTalkgroup;
|
||||
private Alias mTalkgroupAlias;
|
||||
private int mChannelNumber;
|
||||
private long mFrequency;
|
||||
private LCNTracker mLCNTracker = new LCNTracker();
|
||||
|
||||
public LTRStandardDecoderState( AliasList aliasList )
|
||||
{
|
||||
@@ -70,171 +82,126 @@ public class LTRStandardDecoderState extends DecoderState
|
||||
{
|
||||
}
|
||||
|
||||
private LTRCallEvent getCurrentCallEvent()
|
||||
{
|
||||
return (LTRCallEvent)mCurrentCallEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( Message message )
|
||||
{
|
||||
if( message.isValid() )
|
||||
if( message.isValid() && message instanceof LTRStandardMessage )
|
||||
{
|
||||
if( message instanceof LTRStandardOSWMessage )
|
||||
switch( ((LTRStandardMessage)message).getMessageType() )
|
||||
{
|
||||
LTRStandardOSWMessage ltr = ((LTRStandardOSWMessage)message);
|
||||
|
||||
switch( ltr.getMessageType() )
|
||||
{
|
||||
case CA_STRT:
|
||||
if( 0 < ltr.getChannel() && ltr.getChannel() <=20 )
|
||||
{
|
||||
/* If we haven't captured the LCN yet ... */
|
||||
if( mChannelNumber == 0 )
|
||||
{
|
||||
mChannelNumber = ltr.getChannel();
|
||||
broadcast( ChangedAttribute.CHANNEL_NUMBER );
|
||||
}
|
||||
case CA_STRT:
|
||||
CallMessage start = (CallMessage)message;
|
||||
|
||||
int channel = start.getChannel();
|
||||
|
||||
mLCNTracker.processCallChannel( channel );
|
||||
|
||||
mLCNTracker.processFreeChannel( start.getFree() );
|
||||
|
||||
/* If this call event is for this channel, then update
|
||||
* talkgroup and alias */
|
||||
if( ltr.getChannel() == mChannelNumber )
|
||||
{
|
||||
mTalkgroup = ltr.getTalkgroupID();
|
||||
broadcast( ChangedAttribute.TO_TALKGROUP );
|
||||
|
||||
mTalkgroupAlias = ltr.getTalkgroupIDAlias();
|
||||
broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS );
|
||||
|
||||
LTRCallEvent current = getCurrentCallEvent();
|
||||
//Only process calls on this LCN, or call detects for
|
||||
//talkgroups that are homed on this LCN
|
||||
if( mLCNTracker.isValidChannel( channel ) &&
|
||||
( mLCNTracker.isCurrentChannel( channel ) ||
|
||||
mLCNTracker.isCurrentChannel( start.getHomeRepeater() ) ) )
|
||||
{
|
||||
LTRCallEvent event = mActiveCalls.get( channel );
|
||||
|
||||
if( event == null ||
|
||||
!event.isMatchingTalkgroup( start.getToID() ) )
|
||||
{
|
||||
//Check for different talkgroup
|
||||
if( event != null )
|
||||
{
|
||||
event.end();
|
||||
mActiveCalls.remove( channel );
|
||||
}
|
||||
|
||||
/* Detect when we haven't reset from the previous
|
||||
* call and now have a new call coming in with
|
||||
* a different talkgroup */
|
||||
if( current != null && isDifferentTalkgroup( mTalkgroup ) )
|
||||
{
|
||||
mCurrentCallEvent.end();
|
||||
broadcast( mCurrentCallEvent );
|
||||
mCurrentCallEvent = null;
|
||||
}
|
||||
|
||||
if( current == null )
|
||||
{
|
||||
mCurrentCallEvent =
|
||||
new LTRCallEvent.Builder(
|
||||
DecoderType.LTR_STANDARD, CallEventType.CALL )
|
||||
.to( ltr.getTalkgroupID() )
|
||||
.aliasList( getAliasList() )
|
||||
.channel( String.valueOf( ltr.getChannel() ) )
|
||||
.frequency( mFrequency )
|
||||
.build();
|
||||
boolean current = mLCNTracker.isCurrentChannel( channel );
|
||||
|
||||
event = new LTRCallEvent.Builder(
|
||||
DecoderType.LTR_STANDARD,
|
||||
current ? CallEventType.CALL : CallEventType.CALL_DETECT )
|
||||
.to( start.getToID() )
|
||||
.aliasList( getAliasList() )
|
||||
.channel( start.getChannelFormatted() )
|
||||
.frequency( current ? mFrequency : 0 )
|
||||
.build();
|
||||
|
||||
mActiveCalls.put( channel, event );
|
||||
|
||||
broadcast( event );
|
||||
|
||||
if( mLCNTracker.isCurrentChannel( channel ) )
|
||||
{
|
||||
mTalkgroup = start.getToID();
|
||||
broadcast( ChangedAttribute.TO_TALKGROUP );
|
||||
|
||||
processTalkgroup( mTalkgroup );
|
||||
|
||||
mTalkgroupAlias = start.getToIDAlias();
|
||||
broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS );
|
||||
|
||||
broadcast( mCurrentCallEvent );
|
||||
|
||||
broadcast( new Metadata( MetadataType.TO,
|
||||
mTalkgroup, mTalkgroupAlias, true ) );
|
||||
broadcast( new Metadata( MetadataType.TO,
|
||||
mTalkgroup, mTalkgroupAlias, true ) );
|
||||
}
|
||||
}
|
||||
|
||||
broadcast( new DecoderStateEvent( this,
|
||||
Event.CONTINUATION, State.CALL ) );
|
||||
}
|
||||
break;
|
||||
case CA_ENDD:
|
||||
CallEndMessage end = (CallEndMessage)message;
|
||||
|
||||
broadcast( new DecoderStateEvent( this,
|
||||
Event.START, State.CALL ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcast( new DecoderStateEvent( this,
|
||||
Event.CONTINUATION, State.CALL ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CA_ENDD:
|
||||
mTalkgroup = ltr.getTalkgroupID();
|
||||
broadcast( ChangedAttribute.TO_TALKGROUP );
|
||||
int repeater = end.getHomeRepeater();
|
||||
|
||||
mLCNTracker.processCallChannel( repeater );
|
||||
|
||||
if( mLCNTracker.isCurrentChannel( repeater ) )
|
||||
{
|
||||
mTalkgroup = end.getToID();
|
||||
broadcast( ChangedAttribute.TO_TALKGROUP );
|
||||
|
||||
processTalkgroup( mTalkgroup );
|
||||
|
||||
mTalkgroupAlias = end.getToIDAlias();
|
||||
broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS );
|
||||
|
||||
mTalkgroupAlias = ltr.getTalkgroupIDAlias();
|
||||
broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS );
|
||||
LTRCallEvent event = mActiveCalls.remove( repeater );
|
||||
|
||||
if( event != null )
|
||||
{
|
||||
event.end();
|
||||
broadcast( event );
|
||||
broadcast( new DecoderStateEvent( this, Event.END, State.FADE ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SY_IDLE:
|
||||
IdleMessage idle = (IdleMessage)message;
|
||||
|
||||
if( mCurrentCallEvent != null )
|
||||
{
|
||||
mCurrentCallEvent.end();
|
||||
broadcast( mCurrentCallEvent );
|
||||
broadcast( new DecoderStateEvent( this, Event.END, State.FADE ) );
|
||||
mCurrentCallEvent = null;
|
||||
}
|
||||
|
||||
int home = ltr.getHomeRepeater();
|
||||
|
||||
if( 0 < home && home <= 20 )
|
||||
{
|
||||
String talkgroup = ltr.getTalkgroupID( false );
|
||||
|
||||
if( mTalkgroupsFirstHeard.contains( talkgroup ) )
|
||||
{
|
||||
mTalkgroups.add( talkgroup );
|
||||
}
|
||||
else
|
||||
{
|
||||
mTalkgroupsFirstHeard.add( talkgroup );
|
||||
}
|
||||
}
|
||||
int lcn = idle.getChannel();
|
||||
|
||||
int channel = ltr.getChannel();
|
||||
|
||||
if( 0 < channel && channel <= 20 )
|
||||
{
|
||||
if( channel == home )
|
||||
{
|
||||
if( mChannelNumber != channel )
|
||||
{
|
||||
mChannelNumber = channel;
|
||||
broadcast( ChangedAttribute.CHANNEL_NUMBER );
|
||||
}
|
||||
|
||||
mActiveLCNs.add( channel );
|
||||
}
|
||||
|
||||
int free = ltr.getFree();
|
||||
|
||||
if( 0 < free && free <= 20 )
|
||||
{
|
||||
mActiveLCNs.add( free );
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case SY_IDLE:
|
||||
int idleChannel = ltr.getChannel();
|
||||
|
||||
if( idleChannel == ltr.getHomeRepeater() &&
|
||||
idleChannel == ltr.getFree() )
|
||||
{
|
||||
if( mChannelNumber != idleChannel )
|
||||
{
|
||||
mChannelNumber = idleChannel;
|
||||
broadcast( ChangedAttribute.CHANNEL_NUMBER );
|
||||
}
|
||||
|
||||
mActiveLCNs.add( idleChannel );
|
||||
}
|
||||
broadcast( new DecoderStateEvent( this,
|
||||
Event.CONTINUATION, State.IDLE ) );
|
||||
break;
|
||||
case UN_KNWN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mLCNTracker.processCallChannel( lcn );
|
||||
|
||||
break;
|
||||
case UN_KNWN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the talkgroup is different than the talkgroup specified in
|
||||
* the current call event
|
||||
*/
|
||||
private boolean isDifferentTalkgroup( String talkgroup )
|
||||
|
||||
private void processTalkgroup( String talkgroup )
|
||||
{
|
||||
return talkgroup != null &&
|
||||
mCurrentCallEvent != null &&
|
||||
mCurrentCallEvent.getToID() != null &&
|
||||
!mCurrentCallEvent.getToID().contentEquals( talkgroup );
|
||||
if( mTalkgroupsFirstHeard.contains( talkgroup ) )
|
||||
{
|
||||
mTalkgroups.add( talkgroup );
|
||||
}
|
||||
else
|
||||
{
|
||||
mTalkgroupsFirstHeard.add( talkgroup );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,8 +212,7 @@ public class LTRStandardDecoderState extends DecoderState
|
||||
mActiveCalls.clear();
|
||||
mTalkgroupsFirstHeard.clear();
|
||||
mTalkgroups.clear();
|
||||
mActiveLCNs.clear();
|
||||
mChannelNumber = 0;
|
||||
mLCNTracker.reset();
|
||||
|
||||
resetState();
|
||||
}
|
||||
@@ -256,13 +222,20 @@ public class LTRStandardDecoderState extends DecoderState
|
||||
*/
|
||||
private void resetState()
|
||||
{
|
||||
if( mCurrentCallEvent != null )
|
||||
for( Integer key: mActiveCalls.keySet() )
|
||||
{
|
||||
mCurrentCallEvent.setEnd( System.currentTimeMillis() );
|
||||
broadcast( mCurrentCallEvent );
|
||||
mCurrentCallEvent = null;
|
||||
LTRCallEvent event = mActiveCalls.get( key );
|
||||
|
||||
if( event != null )
|
||||
{
|
||||
event.end();
|
||||
|
||||
broadcast( event );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mActiveCalls.clear();
|
||||
|
||||
mTalkgroup = null;
|
||||
broadcast( ChangedAttribute.TO_TALKGROUP );
|
||||
|
||||
@@ -282,12 +255,12 @@ public class LTRStandardDecoderState extends DecoderState
|
||||
|
||||
public boolean hasChannelNumber()
|
||||
{
|
||||
return mChannelNumber != 0;
|
||||
return mLCNTracker.getCurrentChannel() != 0;
|
||||
}
|
||||
|
||||
public int getChannelNumber()
|
||||
{
|
||||
return mChannelNumber;
|
||||
return mLCNTracker.getCurrentChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -322,28 +295,28 @@ public class LTRStandardDecoderState extends DecoderState
|
||||
|
||||
sb.append( "Monitored LCN: " );
|
||||
|
||||
if( mChannelNumber > 0 )
|
||||
if( hasChannelNumber() )
|
||||
{
|
||||
sb.append( mChannelNumber );
|
||||
sb.append( getChannelNumber() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "unknown" );
|
||||
sb.append( "*Insufficient Data*" );
|
||||
}
|
||||
|
||||
sb.append( "\n" );
|
||||
|
||||
Integer[] lcns = mActiveLCNs.toArray( new Integer[0] );
|
||||
|
||||
sb.append( "Active LCNs:\t" );
|
||||
|
||||
List<Integer> lcns = mLCNTracker.getActiveLCNs();
|
||||
|
||||
if( lcns.length > 0 )
|
||||
if( lcns.size() > 0 )
|
||||
{
|
||||
sb.append( Arrays.toString( lcns ) );
|
||||
sb.append( mLCNTracker.getActiveLCNs() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "none" );
|
||||
sb.append( "*Insufficient Data*" );
|
||||
}
|
||||
sb.append( "\n\n" );
|
||||
|
||||
@@ -355,19 +328,15 @@ public class LTRStandardDecoderState extends DecoderState
|
||||
}
|
||||
else
|
||||
{
|
||||
Iterator<String> it = mTalkgroups.iterator();
|
||||
|
||||
while( it.hasNext() )
|
||||
for( String talkgroup: mTalkgroups )
|
||||
{
|
||||
String tgid = it.next();
|
||||
|
||||
sb.append( " " );
|
||||
sb.append( formatTalkgroup( tgid ) );
|
||||
sb.append( talkgroup );
|
||||
sb.append( " " );
|
||||
|
||||
if( hasAliasList() )
|
||||
{
|
||||
Alias alias = getAliasList().getTalkgroupAlias( tgid );
|
||||
Alias alias = getAliasList().getTalkgroupAlias( talkgroup );
|
||||
|
||||
if( alias != null )
|
||||
{
|
||||
@@ -376,30 +345,147 @@ public class LTRStandardDecoderState extends DecoderState
|
||||
}
|
||||
|
||||
sb.append( "\n" );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String formatTalkgroup( String talkgroup )
|
||||
/**
|
||||
* Tracks the set of call and free channels for a system in order to
|
||||
* dynamically determine the current LCN and minimize false triggers from
|
||||
* bogus decoded LTR messages. Tracks the number of occurances of each
|
||||
* LCN and uses a dynamic threshold to determine LCN validity.
|
||||
*/
|
||||
public class LCNTracker
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
private static final int DEFAULT_COUNT = 10;
|
||||
private int[] mCallLCNCounts;
|
||||
private int[] mFreeLCNCounts;
|
||||
private int mCallHighestCount;
|
||||
private int mFreeHighestCount;
|
||||
private int mCurrentLCN;
|
||||
|
||||
if( talkgroup.length() == 6 )
|
||||
public LCNTracker()
|
||||
{
|
||||
sb.append( talkgroup.substring( 0, 1 ) );
|
||||
sb.append( "-" );
|
||||
sb.append( talkgroup.substring( 1, 3 ) );
|
||||
sb.append( "-" );
|
||||
sb.append( talkgroup.substring( 3, 6 ) );
|
||||
|
||||
return sb.toString();
|
||||
reset();
|
||||
}
|
||||
else
|
||||
|
||||
public void logStatistics()
|
||||
{
|
||||
return talkgroup;
|
||||
for( int x = 1; x <= 20; x++ )
|
||||
{
|
||||
mLog.debug( "Call " + x + ": " + mCallLCNCounts[ x ] );
|
||||
}
|
||||
mLog.debug( "Call Highest Count: " + mCallHighestCount );
|
||||
for( int x = 1; x <= 20; x++ )
|
||||
{
|
||||
mLog.debug( "Free " + x + ": " + mFreeLCNCounts[ x ] );
|
||||
}
|
||||
mLog.debug( "Free Highest Count: " + mFreeHighestCount );
|
||||
|
||||
mLog.debug( "Current LCN: " + mCurrentLCN );
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
//Dim channel arrays to 21 -- ignore the 0 index
|
||||
mCallLCNCounts = new int[ 21 ];
|
||||
mFreeLCNCounts = new int[ 21 ];
|
||||
mCallHighestCount = 3;
|
||||
mFreeHighestCount = DEFAULT_COUNT;
|
||||
mCurrentLCN = 0;
|
||||
}
|
||||
|
||||
public boolean isCurrentChannel( int channel )
|
||||
{
|
||||
if( mCurrentLCN == 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channel == mCurrentLCN;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCurrentChannel()
|
||||
{
|
||||
return mCurrentLCN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the channel is valid based on the observed current and
|
||||
* free channels reported by the system. Tracks the count of each
|
||||
* reported free channel the highest free channel count is used as a
|
||||
* threshold where a channel is valid when its count exceeds 20% of the
|
||||
* highest free channel count. A channel is also valid when it is
|
||||
* the currently monitored channel.
|
||||
*/
|
||||
public boolean isValidChannel( int channel )
|
||||
{
|
||||
if( isCurrentChannel( channel ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int count = mFreeLCNCounts[ channel ];
|
||||
|
||||
int threshold = (int)( (double)mFreeHighestCount * 0.2 );
|
||||
|
||||
return count >= threshold;
|
||||
}
|
||||
|
||||
public void processCallChannel( int channel )
|
||||
{
|
||||
if( 1 <= channel && channel <= 20 )
|
||||
{
|
||||
mCallLCNCounts[ channel ]++;
|
||||
|
||||
if( mCallLCNCounts[ channel ] > mCallHighestCount )
|
||||
{
|
||||
mCallHighestCount = mCallLCNCounts[ channel ];
|
||||
mCurrentLCN = channel;
|
||||
|
||||
broadcast( ChangedAttribute.CHANNEL_NUMBER );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void processFreeChannel( int channel )
|
||||
{
|
||||
if( 1 <= channel && channel <= 20 )
|
||||
{
|
||||
mFreeLCNCounts[ channel ]++;
|
||||
|
||||
if( mFreeLCNCounts[ channel ] > mFreeHighestCount )
|
||||
{
|
||||
mFreeHighestCount = mFreeLCNCounts[ channel ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Integer> getActiveLCNs()
|
||||
{
|
||||
List<Integer> active = new ArrayList<>();
|
||||
|
||||
if( mFreeHighestCount > DEFAULT_COUNT )
|
||||
{
|
||||
for( int x = 1; x <= 20; x++ )
|
||||
{
|
||||
if( mCurrentLCN != 0 && isCurrentChannel( x ) )
|
||||
{
|
||||
active.add( x );
|
||||
}
|
||||
else if( isValidChannel( x ) )
|
||||
{
|
||||
active.add( x );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return active;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.ltrstandard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import map.Plottable;
|
||||
import message.MessageDirection;
|
||||
import message.MessageType;
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import bits.BinaryMessage;
|
||||
|
||||
public class LTRStandardISWMessage extends LTRStandardMessage
|
||||
{
|
||||
private static final int sCALL_END = 31;
|
||||
private static final int sIDLE = 255;
|
||||
|
||||
public LTRStandardISWMessage( BinaryMessage message, AliasList list )
|
||||
{
|
||||
super( message, MessageDirection.OSW, list );
|
||||
mMessageType = getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append( mDatestampFormatter.format(
|
||||
new Date( System.currentTimeMillis() ) ) );
|
||||
sb.append( " LTR OSW [" );
|
||||
sb.append( mCRC.getAbbreviation() );
|
||||
sb.append( "] " );
|
||||
sb.append( getMessage() );
|
||||
pad( sb, 100 );
|
||||
sb.append( mMessage.toString() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
switch( mMessageType )
|
||||
{
|
||||
case SY_IDLE:
|
||||
sb.append( "IDLE AREA:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " LCN:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " HOME:" );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( " GRP:" );
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
sb.append( " FREE:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
break;
|
||||
case CA_STRT:
|
||||
sb.append( "CALL LCN:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " TG [ " );
|
||||
sb.append( getTalkgroupID() );
|
||||
sb.append( "/" );
|
||||
sb.append( getTalkgroupIDAlias() );
|
||||
sb.append( " ] FREE:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
break;
|
||||
case CA_ENDD:
|
||||
sb.append( "END* AREA:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " LCN:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " TG [" );
|
||||
sb.append( getTalkgroupID() );
|
||||
sb.append( "/" );
|
||||
sb.append( getTalkgroupIDAlias() );
|
||||
sb.append( "] FREE:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
break;
|
||||
default:
|
||||
sb.append( "UNKNOWN A:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " C:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " H:" );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( " G:" );
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
sb.append( " F:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getTalkgroupID()
|
||||
{
|
||||
return getTalkgroupID( true );
|
||||
}
|
||||
|
||||
public String getTalkgroupID( boolean format )
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( getArea() );
|
||||
|
||||
if( format )
|
||||
{
|
||||
sb.append( "-" );
|
||||
}
|
||||
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
|
||||
if( format )
|
||||
{
|
||||
sb.append( "-" );
|
||||
}
|
||||
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Alias getTalkgroupIDAlias()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append( getArea() );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
|
||||
return mAliasList.getTalkgroupAlias( sb.toString() );
|
||||
}
|
||||
|
||||
public MessageType getType()
|
||||
{
|
||||
MessageType retVal = MessageType.UN_KNWN;
|
||||
|
||||
int group = getGroup();
|
||||
|
||||
if( group == sIDLE )
|
||||
{
|
||||
retVal = MessageType.SY_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int channel = getChannel();
|
||||
|
||||
if( channel == sCALL_END )
|
||||
{
|
||||
retVal = MessageType.CA_ENDD;
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = MessageType.CA_STRT;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFromID()
|
||||
{
|
||||
if( mMessageType == MessageType.CA_STRT ||
|
||||
mMessageType == MessageType.CA_ENDD )
|
||||
{
|
||||
return getTalkgroupID();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getFromIDAlias()
|
||||
{
|
||||
if( mMessageType == MessageType.CA_STRT ||
|
||||
mMessageType == MessageType.CA_ENDD )
|
||||
{
|
||||
return getTalkgroupIDAlias();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plottable getPlottable()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a listing of aliases contained in the message.
|
||||
*/
|
||||
public List<Alias> getAliases()
|
||||
{
|
||||
List<Alias> aliases = new ArrayList<Alias>();
|
||||
|
||||
Alias from = getFromIDAlias();
|
||||
|
||||
if( from != null )
|
||||
{
|
||||
aliases.add( from );
|
||||
}
|
||||
|
||||
Alias to = getToIDAlias();
|
||||
|
||||
if( to != null )
|
||||
{
|
||||
aliases.add( to );
|
||||
}
|
||||
|
||||
return aliases;
|
||||
}
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.ltrstandard;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import message.Message;
|
||||
import message.MessageDirection;
|
||||
import message.MessageType;
|
||||
import module.decode.DecoderType;
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import bits.BinaryMessage;
|
||||
import edac.CRC;
|
||||
import edac.CRCLTR;
|
||||
|
||||
public abstract class LTRStandardMessage extends Message
|
||||
{
|
||||
protected static final String sUNKNOWN = "**UNKNOWN**";
|
||||
protected static final int sINT_NULL_VALUE = -1;
|
||||
protected static final double sDOUBLE_NULL_VALUE = -1.0D;
|
||||
protected SimpleDateFormat mDatestampFormatter =
|
||||
new SimpleDateFormat( "yyyyMMdd HHmmss" );
|
||||
protected DecimalFormat mDecimalFormatter = new DecimalFormat("0.00000");
|
||||
|
||||
protected static final int[] sSYNC = { 8,7,6,5,4,3,2,1,0 };
|
||||
protected static final int[] sAREA = { 9 };
|
||||
protected static final int[] sCHANNEL = { 14,13,12,11,10 };
|
||||
protected static final int[] sHOME_REPEATER = { 19,18,17,16,15 };
|
||||
protected static final int[] sGROUP = { 27,26,25,24,23,22,21,20 };
|
||||
protected static final int[] sFREE = { 32,31,30,29,28 };
|
||||
protected static final int[] sCRC = { 39,38,37,36,35,34,33 };
|
||||
|
||||
protected BinaryMessage mMessage;
|
||||
protected MessageType mMessageType;
|
||||
protected CRC mCRC;
|
||||
protected AliasList mAliasList;
|
||||
|
||||
public LTRStandardMessage( BinaryMessage message,
|
||||
MessageDirection direction,
|
||||
AliasList list )
|
||||
{
|
||||
mMessage = message;
|
||||
mCRC = CRCLTR.check( message, direction );
|
||||
mAliasList = list;
|
||||
}
|
||||
|
||||
public MessageType getMessageType()
|
||||
{
|
||||
return mMessageType;
|
||||
}
|
||||
|
||||
public boolean isValid()
|
||||
{
|
||||
return mCRC != CRC.FAILED_CRC && mCRC != CRC.FAILED_PARITY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends spaces to the end of the stringbuilder to make it length long
|
||||
*/
|
||||
protected void pad( StringBuilder sb, int length )
|
||||
{
|
||||
while( sb.length() < length )
|
||||
{
|
||||
sb.append( " " );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBinaryMessage()
|
||||
{
|
||||
return mMessage.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value formatted in hex notation.
|
||||
*
|
||||
* @param value - integer value
|
||||
* @return - hex digits returned
|
||||
*/
|
||||
protected static String getHex( int value, int digits )
|
||||
{
|
||||
return String.format( "%0" + digits + "X", value );
|
||||
}
|
||||
|
||||
protected int getInt( int[] bits )
|
||||
{
|
||||
int retVal = 0;
|
||||
|
||||
for( int x = 0; x < bits.length; x++ )
|
||||
{
|
||||
if( mMessage.get( bits[ x ] ) )
|
||||
{
|
||||
retVal += 1<<x;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads an integer value with additional zeroes to make it decimalPlaces long
|
||||
*/
|
||||
public String format( int number, int decimalPlaces )
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int paddingRequired = decimalPlaces - ( String.valueOf( number ).length() );
|
||||
|
||||
for( int x = 0; x < paddingRequired; x++)
|
||||
{
|
||||
sb.append( "0" );
|
||||
}
|
||||
|
||||
sb.append( number );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String format( String val, int places )
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( val );
|
||||
|
||||
while( sb.length() < places )
|
||||
{
|
||||
sb.append( " " );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public CRC getCRC()
|
||||
{
|
||||
return mCRC;
|
||||
}
|
||||
|
||||
public int getArea()
|
||||
{
|
||||
return getInt( sAREA );
|
||||
}
|
||||
|
||||
public int getChannel()
|
||||
{
|
||||
return getInt( sCHANNEL );
|
||||
}
|
||||
|
||||
public int getHomeRepeater()
|
||||
{
|
||||
return getInt( sHOME_REPEATER );
|
||||
}
|
||||
|
||||
public int getGroup()
|
||||
{
|
||||
return getInt( sGROUP );
|
||||
}
|
||||
|
||||
public String getTalkgroupID()
|
||||
{
|
||||
return getTalkgroupID( true );
|
||||
}
|
||||
|
||||
public String getTalkgroupID( boolean format )
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( getArea() );
|
||||
|
||||
if( format )
|
||||
{
|
||||
sb.append( "-" );
|
||||
}
|
||||
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
|
||||
if( format )
|
||||
{
|
||||
sb.append( "-" );
|
||||
}
|
||||
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Alias getTalkgroupIDAlias()
|
||||
{
|
||||
return mAliasList.getTalkgroupAlias( getTalkgroupID() );
|
||||
}
|
||||
|
||||
public int getFree()
|
||||
{
|
||||
return getInt( sFREE );
|
||||
}
|
||||
|
||||
public int getCRCChecksum()
|
||||
{
|
||||
return getInt( sCRC );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol()
|
||||
{
|
||||
return DecoderType.LTR_STANDARD.getDisplayString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventType()
|
||||
{
|
||||
if( mMessageType != null )
|
||||
{
|
||||
return mMessageType.getDisplayText();
|
||||
}
|
||||
else
|
||||
{
|
||||
return MessageType.UN_KNWN.getDisplayText();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToID()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getToIDAlias()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorStatus()
|
||||
{
|
||||
return mCRC.getDisplayText();
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import java.util.List;
|
||||
|
||||
import message.Message;
|
||||
import message.MessageType;
|
||||
import module.decode.ltrstandard.message.LTRStandardMessage;
|
||||
import filter.Filter;
|
||||
import filter.FilterElement;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014,2015 Dennis Sheirer
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -19,9 +19,16 @@ package module.decode.ltrstandard;
|
||||
|
||||
import message.Message;
|
||||
import message.MessageDirection;
|
||||
import module.decode.ltrstandard.message.CallEndMessage;
|
||||
import module.decode.ltrstandard.message.CallMessage;
|
||||
import module.decode.ltrstandard.message.IdleMessage;
|
||||
import module.decode.ltrstandard.message.LTRStandardMessage;
|
||||
import module.decode.ltrstandard.message.UnknownMessage;
|
||||
import sample.Listener;
|
||||
import alias.AliasList;
|
||||
import bits.BinaryMessage;
|
||||
import edac.CRC;
|
||||
import edac.CRCLTR;
|
||||
|
||||
public class LTRStandardMessageProcessor implements Listener<BinaryMessage>
|
||||
{
|
||||
@@ -29,6 +36,12 @@ public class LTRStandardMessageProcessor implements Listener<BinaryMessage>
|
||||
private AliasList mAliasList;
|
||||
private Listener<Message> mMessageListener;
|
||||
|
||||
/**
|
||||
* Processes raw binary messages and converts them to the correct message class
|
||||
*
|
||||
* @param direction - inbound (ISW) or outbound (OSW)
|
||||
* @param list - alias list
|
||||
*/
|
||||
public LTRStandardMessageProcessor( MessageDirection direction, AliasList list )
|
||||
{
|
||||
mDirection = direction;
|
||||
@@ -36,27 +49,66 @@ public class LTRStandardMessageProcessor implements Listener<BinaryMessage>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( BinaryMessage buffer )
|
||||
public void receive( BinaryMessage binaryMessage )
|
||||
{
|
||||
if( mMessageListener != null )
|
||||
{
|
||||
LTRStandardMessage message;
|
||||
|
||||
if( mDirection == MessageDirection.OSW )
|
||||
//Inbound Status Word (ISW) is a bit-flipped version of the Outbound
|
||||
//(OSW), so flip the bits and process it as an OSW
|
||||
if( mDirection == MessageDirection.ISW )
|
||||
{
|
||||
message = new LTRStandardOSWMessage( buffer, mAliasList );
|
||||
binaryMessage.flip( 0, 40 );
|
||||
}
|
||||
else
|
||||
|
||||
CRC crc = CRCLTR.check( binaryMessage, mDirection );
|
||||
|
||||
if( crc != CRC.FAILED_CRC &&
|
||||
crc != CRC.FAILED_PARITY )
|
||||
{
|
||||
buffer.flip( 0, 40 );
|
||||
LTRStandardMessage message;
|
||||
|
||||
message = new LTRStandardISWMessage( buffer, mAliasList );
|
||||
int channel = binaryMessage.getInt( LTRStandardMessage.CHANNEL );
|
||||
int home = binaryMessage.getInt( LTRStandardMessage.HOME_REPEATER );
|
||||
int free = binaryMessage.getInt( LTRStandardMessage.FREE );
|
||||
int group = binaryMessage.getInt( LTRStandardMessage.GROUP );
|
||||
|
||||
if( isValidChannel( channel ) &&
|
||||
isValidChannel( home ) &&
|
||||
isValidChannel( free ) )
|
||||
{
|
||||
if( channel == free && group == 255 )
|
||||
{
|
||||
message = new IdleMessage( binaryMessage, mDirection, mAliasList, crc );
|
||||
}
|
||||
else
|
||||
{
|
||||
message = new CallMessage( binaryMessage, mDirection, mAliasList, crc );
|
||||
}
|
||||
}
|
||||
else if( channel == 31 &&
|
||||
isValidChannel( home ) &&
|
||||
isValidChannel( free ) )
|
||||
{
|
||||
message = new CallEndMessage( binaryMessage, mDirection, mAliasList, crc );
|
||||
}
|
||||
else
|
||||
{
|
||||
message = new UnknownMessage( binaryMessage, mDirection, mAliasList, crc );
|
||||
}
|
||||
|
||||
mMessageListener.receive( message );
|
||||
}
|
||||
|
||||
mMessageListener.receive( message );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the channel (LCN) number to ensure it is in the range 1 -20
|
||||
*/
|
||||
private boolean isValidChannel( int channel )
|
||||
{
|
||||
return ( 1 <= channel && channel <= 20 );
|
||||
}
|
||||
|
||||
public void setMessageListener( Listener<Message> listener )
|
||||
{
|
||||
mMessageListener = listener;
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.ltrstandard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import map.Plottable;
|
||||
import message.MessageDirection;
|
||||
import message.MessageType;
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import bits.BinaryMessage;
|
||||
|
||||
public class LTRStandardOSWMessage extends LTRStandardMessage
|
||||
{
|
||||
private static final int sCALL_END = 31;
|
||||
private static final int sIDLE = 255;
|
||||
|
||||
public LTRStandardOSWMessage( BinaryMessage message, AliasList list )
|
||||
{
|
||||
super( message, MessageDirection.OSW, list );
|
||||
mMessageType = getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append( mDatestampFormatter.format(
|
||||
new Date( System.currentTimeMillis() ) ) );
|
||||
sb.append( " LTR OSW [" );
|
||||
sb.append( mCRC.getAbbreviation() );
|
||||
sb.append( "] " );
|
||||
sb.append( getMessage() );
|
||||
pad( sb, 100 );
|
||||
sb.append( mMessage.toString() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
switch( mMessageType )
|
||||
{
|
||||
case SY_IDLE:
|
||||
sb.append( "IDLE AREA:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " LCN:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " HOME:" );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( " GRP:" );
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
sb.append( " FREE:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
break;
|
||||
case CA_STRT:
|
||||
sb.append( "CALL LCN:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " TG [ " );
|
||||
sb.append( getTalkgroupID() );
|
||||
sb.append( "/" );
|
||||
Alias alias = getTalkgroupIDAlias();
|
||||
if( alias != null )
|
||||
{
|
||||
sb.append( getTalkgroupIDAlias().getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "UNKNOWN" );
|
||||
}
|
||||
sb.append( " ] FREE:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
break;
|
||||
case CA_ENDD:
|
||||
sb.append( "END* AREA:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " LCN:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " TG [" );
|
||||
sb.append( getTalkgroupID() );
|
||||
sb.append( "/" );
|
||||
Alias endAlias = getTalkgroupIDAlias();
|
||||
if( endAlias != null )
|
||||
{
|
||||
sb.append( getTalkgroupIDAlias().getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "UNKNOWN" );
|
||||
}
|
||||
sb.append( "] FREE:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
break;
|
||||
default:
|
||||
sb.append( "UNKNOWN A:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " C:" );
|
||||
sb.append( format( getChannel(), 2 ) );
|
||||
sb.append( " H:" );
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
sb.append( " G:" );
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
sb.append( " F:" );
|
||||
sb.append( format( getFree(), 2 ) );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getTalkgroupID()
|
||||
{
|
||||
return getTalkgroupID( true );
|
||||
}
|
||||
|
||||
public String getTalkgroupID( boolean format )
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( getArea() );
|
||||
|
||||
if( format )
|
||||
{
|
||||
sb.append( "-" );
|
||||
}
|
||||
|
||||
sb.append( format( getHomeRepeater(), 2 ) );
|
||||
|
||||
if( format )
|
||||
{
|
||||
sb.append( "-" );
|
||||
}
|
||||
|
||||
sb.append( format( getGroup(), 3 ) );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Alias getTalkgroupIDAlias()
|
||||
{
|
||||
return mAliasList.getTalkgroupAlias( getTalkgroupID() );
|
||||
}
|
||||
|
||||
public MessageType getType()
|
||||
{
|
||||
MessageType retVal = MessageType.UN_KNWN;
|
||||
|
||||
/* Group 255 when the channel equals the free is the IDLE message */
|
||||
if( getGroup() == sIDLE && getChannel() == getFree() )
|
||||
{
|
||||
retVal = MessageType.SY_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int channel = getChannel();
|
||||
|
||||
if( channel == sCALL_END )
|
||||
{
|
||||
retVal = MessageType.CA_ENDD;
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = MessageType.CA_STRT;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFromID()
|
||||
{
|
||||
if( mMessageType == MessageType.CA_STRT ||
|
||||
mMessageType == MessageType.CA_ENDD )
|
||||
{
|
||||
return getTalkgroupID();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getFromIDAlias()
|
||||
{
|
||||
if( mMessageType == MessageType.CA_STRT ||
|
||||
mMessageType == MessageType.CA_ENDD )
|
||||
{
|
||||
return getTalkgroupIDAlias();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plottable getPlottable()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a listing of aliases contained in the message.
|
||||
*/
|
||||
public List<Alias> getAliases()
|
||||
{
|
||||
List<Alias> aliases = new ArrayList<Alias>();
|
||||
|
||||
Alias from = getFromIDAlias();
|
||||
|
||||
if( from != null )
|
||||
{
|
||||
aliases.add( from );
|
||||
}
|
||||
|
||||
Alias to = getToIDAlias();
|
||||
|
||||
if( to != null )
|
||||
{
|
||||
aliases.add( to );
|
||||
}
|
||||
|
||||
return aliases;
|
||||
}
|
||||
}
|
||||
67
src/module/decode/ltrstandard/message/CallEndMessage.java
Normal file
67
src/module/decode/ltrstandard/message/CallEndMessage.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package module.decode.ltrstandard.message;
|
||||
|
||||
import message.MessageDirection;
|
||||
import message.MessageType;
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import bits.BinaryMessage;
|
||||
import edac.CRC;
|
||||
|
||||
public class CallEndMessage extends LTRStandardMessage
|
||||
{
|
||||
public CallEndMessage( BinaryMessage message, MessageDirection direction,
|
||||
AliasList list, CRC crc )
|
||||
{
|
||||
super( message, direction, list, crc );
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType getMessageType()
|
||||
{
|
||||
return MessageType.CA_ENDD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "END* AREA:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " LCN:" );
|
||||
sb.append( getChannelFormatted() );
|
||||
sb.append( " TG [" );
|
||||
sb.append( getToID() );
|
||||
sb.append( "/" );
|
||||
Alias endAlias = getToIDAlias();
|
||||
if( endAlias != null )
|
||||
{
|
||||
sb.append( getToIDAlias().getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "UNKNOWN" );
|
||||
}
|
||||
sb.append( "] FREE:" );
|
||||
sb.append( getFreeFormatted() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
68
src/module/decode/ltrstandard/message/CallMessage.java
Normal file
68
src/module/decode/ltrstandard/message/CallMessage.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package module.decode.ltrstandard.message;
|
||||
|
||||
import message.MessageDirection;
|
||||
import message.MessageType;
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import bits.BinaryMessage;
|
||||
import edac.CRC;
|
||||
|
||||
public class CallMessage extends LTRStandardMessage
|
||||
{
|
||||
public CallMessage( BinaryMessage message, MessageDirection direction,
|
||||
AliasList list, CRC crc )
|
||||
{
|
||||
super( message, direction, list, crc );
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType getMessageType()
|
||||
{
|
||||
return MessageType.CA_STRT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "CALL LCN:" );
|
||||
sb.append( getChannelFormatted() );
|
||||
sb.append( " TG [ " );
|
||||
sb.append( getToID() );
|
||||
sb.append( "/" );
|
||||
|
||||
Alias alias = getToIDAlias();
|
||||
|
||||
if( alias != null )
|
||||
{
|
||||
sb.append( getToIDAlias().getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "UNKNOWN" );
|
||||
}
|
||||
|
||||
sb.append( " ] FREE:" );
|
||||
sb.append( getFreeFormatted() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
58
src/module/decode/ltrstandard/message/IdleMessage.java
Normal file
58
src/module/decode/ltrstandard/message/IdleMessage.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package module.decode.ltrstandard.message;
|
||||
|
||||
import message.MessageDirection;
|
||||
import message.MessageType;
|
||||
import alias.AliasList;
|
||||
import bits.BinaryMessage;
|
||||
import edac.CRC;
|
||||
|
||||
public class IdleMessage extends LTRStandardMessage
|
||||
{
|
||||
public IdleMessage( BinaryMessage message, MessageDirection direction,
|
||||
AliasList list, CRC crc )
|
||||
{
|
||||
super( message, direction, list, crc );
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType getMessageType()
|
||||
{
|
||||
return MessageType.SY_IDLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "IDLE AREA:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " LCN:" );
|
||||
sb.append( getChannelFormatted() );
|
||||
sb.append( " HOME:" );
|
||||
sb.append( getHomeRepeaterFormatted() );
|
||||
sb.append( " GRP:" );
|
||||
sb.append( getGroupFormatted() );
|
||||
sb.append( " FREE:" );
|
||||
sb.append( getFreeFormatted() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
213
src/module/decode/ltrstandard/message/LTRStandardMessage.java
Normal file
213
src/module/decode/ltrstandard/message/LTRStandardMessage.java
Normal file
@@ -0,0 +1,213 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package module.decode.ltrstandard.message;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import message.Message;
|
||||
import message.MessageDirection;
|
||||
import message.MessageType;
|
||||
import module.decode.DecoderType;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import bits.BinaryMessage;
|
||||
import edac.CRC;
|
||||
|
||||
public abstract class LTRStandardMessage extends Message
|
||||
{
|
||||
protected SimpleDateFormat mDatestampFormatter =
|
||||
new SimpleDateFormat( "yyyyMMdd HHmmss" );
|
||||
|
||||
public static final int[] SYNC = { 0,1,2,3,4,5,6,7,8 };
|
||||
public static final int[] AREA = { 9 };
|
||||
public static final int[] CHANNEL = { 10,11,12,13,14 };
|
||||
public static final int[] HOME_REPEATER = { 15,16,17,18,19 };
|
||||
public static final int[] GROUP = { 20,21,22,23,24,25,26,27 };
|
||||
public static final int[] FREE = { 28,29,30,31,32 };
|
||||
public static final int[] CHECKSUM = { 33,34,35,36,37,38,39 };
|
||||
|
||||
protected BinaryMessage mMessage;
|
||||
protected MessageDirection mMessageDirection;
|
||||
protected AliasList mAliasList;
|
||||
protected CRC mCRC;
|
||||
|
||||
public LTRStandardMessage( BinaryMessage message,
|
||||
MessageDirection direction,
|
||||
AliasList list,
|
||||
CRC crc )
|
||||
{
|
||||
mMessage = message;
|
||||
mMessageDirection = direction;
|
||||
mAliasList = list;
|
||||
mCRC = crc;
|
||||
}
|
||||
|
||||
public abstract MessageType getMessageType();
|
||||
|
||||
public boolean isValid()
|
||||
{
|
||||
return mCRC != CRC.FAILED_CRC && mCRC != CRC.FAILED_PARITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append( mDatestampFormatter.format(
|
||||
new Date( System.currentTimeMillis() ) ) );
|
||||
sb.append( " LTR " );
|
||||
sb.append( mMessageDirection.name() );
|
||||
sb.append( " [" );
|
||||
sb.append( mCRC.getAbbreviation() );
|
||||
sb.append( "] " );
|
||||
sb.append( getMessage() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBinaryMessage()
|
||||
{
|
||||
return mMessage.toString();
|
||||
}
|
||||
|
||||
public CRC getCRC()
|
||||
{
|
||||
return mCRC;
|
||||
}
|
||||
|
||||
public int getArea()
|
||||
{
|
||||
return mMessage.getInt( AREA );
|
||||
}
|
||||
|
||||
public int getChannel()
|
||||
{
|
||||
return mMessage.getInt( CHANNEL );
|
||||
}
|
||||
|
||||
public String getChannelFormatted()
|
||||
{
|
||||
return StringUtils.leftPad( String.valueOf( getChannel() ), 2, "0" );
|
||||
}
|
||||
|
||||
public int getHomeRepeater()
|
||||
{
|
||||
return mMessage.getInt( HOME_REPEATER );
|
||||
}
|
||||
|
||||
public String getHomeRepeaterFormatted()
|
||||
{
|
||||
return StringUtils.leftPad( String.valueOf( getHomeRepeater() ), 2, "0" );
|
||||
}
|
||||
|
||||
public int getGroup()
|
||||
{
|
||||
return mMessage.getInt( GROUP );
|
||||
}
|
||||
|
||||
public String getGroupFormatted()
|
||||
{
|
||||
return StringUtils.leftPad( String.valueOf( getGroup() ), 3, "0" );
|
||||
}
|
||||
|
||||
public int getFree()
|
||||
{
|
||||
return mMessage.getInt( FREE );
|
||||
}
|
||||
|
||||
public String getFreeFormatted()
|
||||
{
|
||||
return StringUtils.leftPad( String.valueOf( getFree() ), 2, "0" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFromID()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getFromIDAlias()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToID()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( getArea() );
|
||||
sb.append( "-" );
|
||||
sb.append( getHomeRepeaterFormatted() );
|
||||
sb.append( "-" );
|
||||
sb.append( getGroupFormatted() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getToIDAlias()
|
||||
{
|
||||
return mAliasList.getTalkgroupAlias( getToID() );
|
||||
}
|
||||
|
||||
public List<Alias> getAliases()
|
||||
{
|
||||
List<Alias> aliases = new ArrayList<>();
|
||||
|
||||
Alias talkgroupAlias = getToIDAlias();
|
||||
|
||||
if( talkgroupAlias != null )
|
||||
{
|
||||
aliases.add( talkgroupAlias );
|
||||
}
|
||||
|
||||
return aliases;
|
||||
}
|
||||
|
||||
public int getCRCChecksum()
|
||||
{
|
||||
return mMessage.getInt( CHECKSUM );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol()
|
||||
{
|
||||
return DecoderType.LTR_STANDARD.getDisplayString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventType()
|
||||
{
|
||||
return getMessageType().getDisplayText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorStatus()
|
||||
{
|
||||
return mCRC.getDisplayText();
|
||||
}
|
||||
}
|
||||
58
src/module/decode/ltrstandard/message/UnknownMessage.java
Normal file
58
src/module/decode/ltrstandard/message/UnknownMessage.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
package module.decode.ltrstandard.message;
|
||||
|
||||
import message.MessageDirection;
|
||||
import message.MessageType;
|
||||
import alias.AliasList;
|
||||
import bits.BinaryMessage;
|
||||
import edac.CRC;
|
||||
|
||||
public class UnknownMessage extends LTRStandardMessage
|
||||
{
|
||||
public UnknownMessage( BinaryMessage message, MessageDirection direction,
|
||||
AliasList list, CRC crc )
|
||||
{
|
||||
super( message, direction, list, crc );
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType getMessageType()
|
||||
{
|
||||
return MessageType.UN_KNWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "UNKNOWN AREA:" );
|
||||
sb.append( getArea() );
|
||||
sb.append( " LCN:" );
|
||||
sb.append( getChannelFormatted() );
|
||||
sb.append( " HOME:" );
|
||||
sb.append( getHomeRepeaterFormatted() );
|
||||
sb.append( " GRP:" );
|
||||
sb.append( getGroupFormatted() );
|
||||
sb.append( " FREE:" );
|
||||
sb.append( getFreeFormatted() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
******************************************************************************/
|
||||
package module.decode.state;
|
||||
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -182,8 +183,16 @@ public class ChannelState extends Module implements ICallEventProvider,
|
||||
{
|
||||
if( mRunningMonitor == null && mStateMonitor != null )
|
||||
{
|
||||
mRunningMonitor = mThreadPoolManager.scheduleFixedRate(
|
||||
ThreadType.DECODER, mStateMonitor, 20, TimeUnit.MILLISECONDS );
|
||||
try
|
||||
{
|
||||
mRunningMonitor = mThreadPoolManager.scheduleFixedRate(
|
||||
ThreadType.DECODER, mStateMonitor, 20, TimeUnit.MILLISECONDS );
|
||||
}
|
||||
catch( RejectedExecutionException ree )
|
||||
{
|
||||
mLog.error( "state monitor scheduled task rejected", ree );
|
||||
mMonitoring.set( false );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -372,6 +381,10 @@ public class ChannelState extends Module implements ICallEventProvider,
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.debug( "Can't change from [" + mState + "] to [" + state + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
public class StateMonitor implements Runnable
|
||||
@@ -379,23 +392,35 @@ public class ChannelState extends Module implements ICallEventProvider,
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if( getState() == State.FADE )
|
||||
try
|
||||
{
|
||||
if( mResetTimeout <= System.currentTimeMillis() )
|
||||
if( getState() == State.FADE )
|
||||
{
|
||||
setState( State.END );
|
||||
if( mResetTimeout <= System.currentTimeMillis() )
|
||||
{
|
||||
setState( State.END );
|
||||
}
|
||||
}
|
||||
else if( getState() == State.END )
|
||||
{
|
||||
setState( State.IDLE );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( mFadeTimeout <= System.currentTimeMillis() )
|
||||
{
|
||||
setState( State.FADE );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( getState() == State.END )
|
||||
catch( Exception e )
|
||||
{
|
||||
setState( State.IDLE );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( mFadeTimeout <= System.currentTimeMillis() )
|
||||
{
|
||||
setState( State.FADE );
|
||||
}
|
||||
mLog.error( "Exception thrown while state monitor is running " +
|
||||
"- state [" + getState() +
|
||||
"] current [" + System.currentTimeMillis() +
|
||||
"] mResetTimeout [" + mResetTimeout +
|
||||
"] mFadeTimeout [" + mFadeTimeout +
|
||||
"]", e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user