mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-13 00:57:31 -05:00
Out of memory fixes and updates to the P25 decoder.
Memory Fixes Decreased the decimation process repeat timing so that it runs smaller work chunks more often Decreased scheduled thread pool to 2 hot threads Wrapped all scheduled thread pool runnables in try/catch blocks so that an exception doesn't kill the sample buffer processing thread and cause the buffer to grow unbounded. P25 updates Moved TSBK crc checks into the message framer so that message corrections don't occur after the message is constructed. Added more functionality to the channel state for handling registrations and call events.
This commit is contained in:
@@ -17,6 +17,10 @@
|
||||
******************************************************************************/
|
||||
package decode.p25;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import message.Message;
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
@@ -35,11 +39,19 @@ import decode.p25.message.tsbk.osp.control.UnitDeregistrationAcknowledge;
|
||||
import decode.p25.message.tsbk.osp.voice.GroupVoiceChannelGrant;
|
||||
import decode.p25.message.tsbk.osp.voice.GroupVoiceChannelGrantUpdate;
|
||||
import decode.p25.message.tsbk.osp.voice.GroupVoiceChannelGrantUpdateExplicit;
|
||||
import decode.p25.message.tsbk.osp.voice.TelephoneInterconnectVoiceChannelGrant;
|
||||
import decode.p25.message.tsbk.osp.voice.TelephoneInterconnectVoiceChannelGrantUpdate;
|
||||
import decode.p25.message.tsbk.osp.voice.UnitToUnitAnswerRequest;
|
||||
import decode.p25.message.tsbk.osp.voice.UnitToUnitVoiceChannelGrant;
|
||||
import decode.p25.message.tsbk.osp.voice.UnitToUnitVoiceChannelGrantUpdate;
|
||||
import decode.p25.reference.Opcode;
|
||||
import decode.p25.reference.Vendor;
|
||||
|
||||
public class P25ChannelState extends ChannelState
|
||||
{
|
||||
private HashMap<String,Long> mRegistrations = new HashMap<String,Long>();
|
||||
private String mLastDeRegistration;
|
||||
|
||||
private P25ActivitySummary mActivitySummary;
|
||||
private String mNAC;
|
||||
private String mSystem;
|
||||
@@ -154,99 +166,261 @@ public class P25ChannelState extends ChannelState
|
||||
switch( tsbk.getOpcode() )
|
||||
{
|
||||
case GROUP_VOICE_CHANNEL_GRANT:
|
||||
GroupVoiceChannelGrant gvcg = (GroupVoiceChannelGrant)tsbk;
|
||||
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( mAliasList )
|
||||
.channel( gvcg.getChannelIdentifier() + "-" + gvcg.getChannel() )
|
||||
.details( ( gvcg.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( gvcg.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( gvcg.getDownlinkFrequency() )
|
||||
.from( gvcg.getSourceAddress() )
|
||||
.to( gvcg.getGroupAddress() )
|
||||
.build() );
|
||||
break;
|
||||
case GROUP_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
GroupVoiceChannelGrantUpdate gvcgu =
|
||||
(GroupVoiceChannelGrantUpdate)tsbk;
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( mAliasList )
|
||||
.channel( gvcgu.getChannelID1() + "-" + gvcgu.getChannelNumber1() )
|
||||
.details( ( gvcgu.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( gvcgu.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( gvcgu.getDownlinkFrequency() )
|
||||
.to( gvcgu.getGroupAddress1() )
|
||||
.build() );
|
||||
if( gvcgu.getChannelNumber2() != 0 )
|
||||
{
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( mAliasList )
|
||||
.channel( gvcgu.getChannelID2() + "-" + gvcgu.getChannelNumber2() )
|
||||
.details( ( gvcgu.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( gvcgu.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( gvcgu.getDownlinkFrequency() )
|
||||
.to( gvcgu.getGroupAddress2() )
|
||||
.build() );
|
||||
}
|
||||
break;
|
||||
case GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
|
||||
GroupVoiceChannelGrantUpdateExplicit gvcgue =
|
||||
(GroupVoiceChannelGrantUpdateExplicit)tsbk;
|
||||
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( mAliasList )
|
||||
.channel( gvcgue.getTransmitChannelID() + "-" +
|
||||
gvcgue.getTransmitChannelNumber() )
|
||||
.details( ( gvcgue.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( gvcgue.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( gvcgue.getDownlinkFrequency() )
|
||||
.to( gvcgue.getGroupAddress() )
|
||||
.build() );
|
||||
case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
|
||||
case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
|
||||
case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
processCall( tsbk );
|
||||
break;
|
||||
case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
|
||||
case UNIT_TO_UNIT_ANSWER_REQUEST:
|
||||
UnitToUnitAnswerRequest utuar =
|
||||
(UnitToUnitAnswerRequest)tsbk;
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.PAGE )
|
||||
.aliasList( mAliasList )
|
||||
.details( ( utuar.isEmergency() ? "EMERGENCY" : "" ) )
|
||||
.from( utuar.getSourceAddress() )
|
||||
.to( utuar.getTargetAddress() )
|
||||
.build() );
|
||||
processPage( tsbk );
|
||||
break;
|
||||
case LOCATION_REGISTRATION_RESPONSE:
|
||||
LocationRegistrationResponse lrr =
|
||||
(LocationRegistrationResponse)tsbk;
|
||||
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.REGISTER )
|
||||
.aliasList( mAliasList )
|
||||
.details( "REG:" + lrr.getResponse().name() +
|
||||
" SITE: " + lrr.getRFSSID() + "-" +
|
||||
lrr.getSiteID() )
|
||||
.from( lrr.getTargetAddress() )
|
||||
.to( lrr.getGroupAddress() )
|
||||
.build() );
|
||||
break;
|
||||
case UNIT_DEREGISTRATION_ACKNOWLEDGE:
|
||||
UnitDeregistrationAcknowledge udr =
|
||||
(UnitDeregistrationAcknowledge)tsbk;
|
||||
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.DEREGISTER )
|
||||
.aliasList( mAliasList )
|
||||
.from( udr.getSourceID() )
|
||||
.build() );
|
||||
processRegistration( tsbk );
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a call event message
|
||||
*/
|
||||
private void processCall( TSBKMessage message )
|
||||
{
|
||||
switch( message.getOpcode() )
|
||||
{
|
||||
case GROUP_VOICE_CHANNEL_GRANT:
|
||||
GroupVoiceChannelGrant gvcg = (GroupVoiceChannelGrant)message;
|
||||
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( mAliasList )
|
||||
.channel( gvcg.getChannelIdentifier() + "-" + gvcg.getChannel() )
|
||||
.details( ( gvcg.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( gvcg.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( gvcg.getDownlinkFrequency() )
|
||||
.from( gvcg.getSourceAddress() )
|
||||
.to( gvcg.getGroupAddress() )
|
||||
.build() );
|
||||
break;
|
||||
case GROUP_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
GroupVoiceChannelGrantUpdate gvcgu =
|
||||
(GroupVoiceChannelGrantUpdate)message;
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( mAliasList )
|
||||
.channel( gvcgu.getChannelID1() + "-" + gvcgu.getChannelNumber1() )
|
||||
.details( ( gvcgu.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( gvcgu.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( gvcgu.getDownlinkFrequency1() )
|
||||
.to( gvcgu.getGroupAddress1() )
|
||||
.build() );
|
||||
if( gvcgu.hasChannelNumber2() )
|
||||
{
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( mAliasList )
|
||||
.channel( gvcgu.getChannelID2() + "-" + gvcgu.getChannelNumber2() )
|
||||
.details( ( gvcgu.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( gvcgu.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( gvcgu.getDownlinkFrequency2() )
|
||||
.to( gvcgu.getGroupAddress2() )
|
||||
.build() );
|
||||
}
|
||||
break;
|
||||
case GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
|
||||
GroupVoiceChannelGrantUpdateExplicit gvcgue =
|
||||
(GroupVoiceChannelGrantUpdateExplicit)message;
|
||||
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( mAliasList )
|
||||
.channel( gvcgue.getTransmitChannelID() + "-" +
|
||||
gvcgue.getTransmitChannelNumber() )
|
||||
.details( ( gvcgue.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( gvcgue.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( gvcgue.getDownlinkFrequency() )
|
||||
.to( gvcgue.getGroupAddress() )
|
||||
.build() );
|
||||
break;
|
||||
case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
|
||||
TelephoneInterconnectVoiceChannelGrant tivcg =
|
||||
(TelephoneInterconnectVoiceChannelGrant)message;
|
||||
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( mAliasList )
|
||||
.channel( tivcg.getChannelIdentifier() + "-" +
|
||||
tivcg.getChannel() )
|
||||
.details( ( tivcg.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( tivcg.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( tivcg.getDownlinkFrequency() )
|
||||
.from( tivcg.getSourceAddress() )
|
||||
.to( tivcg.getTargetAddress() )
|
||||
.build() );
|
||||
break;
|
||||
case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
TelephoneInterconnectVoiceChannelGrantUpdate tivcgu =
|
||||
(TelephoneInterconnectVoiceChannelGrantUpdate)message;
|
||||
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( mAliasList )
|
||||
.channel( tivcgu.getChannelIdentifier() + "-" +
|
||||
tivcgu.getChannel() )
|
||||
.details( ( tivcgu.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( tivcgu.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( tivcgu.getDownlinkFrequency() )
|
||||
.from( tivcgu.getSourceAddress() )
|
||||
.to( tivcgu.getTargetAddress() )
|
||||
.build() );
|
||||
break;
|
||||
case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
|
||||
UnitToUnitVoiceChannelGrant uuvcg =
|
||||
(UnitToUnitVoiceChannelGrant)message;
|
||||
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( mAliasList )
|
||||
.channel( uuvcg.getChannelIdentifier() + "-" +
|
||||
uuvcg.getChannel() )
|
||||
.details( ( uuvcg.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( uuvcg.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( uuvcg.getDownlinkFrequency() )
|
||||
.from( uuvcg.getSourceAddress() )
|
||||
.to( uuvcg.getTargetAddress() )
|
||||
.build() );
|
||||
break;
|
||||
case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
UnitToUnitVoiceChannelGrantUpdate uuvcgu =
|
||||
(UnitToUnitVoiceChannelGrantUpdate)message;
|
||||
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( mAliasList )
|
||||
.channel( uuvcgu.getChannelIdentifier() + "-" +
|
||||
uuvcgu.getChannel() )
|
||||
.details( ( uuvcgu.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( uuvcgu.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( uuvcgu.getDownlinkFrequency() )
|
||||
.from( uuvcgu.getSourceAddress() )
|
||||
.to( uuvcgu.getTargetAddress() )
|
||||
.build() );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a unit paging event message
|
||||
*/
|
||||
private void processPage( TSBKMessage message )
|
||||
{
|
||||
if( message.getOpcode() == Opcode.UNIT_TO_UNIT_ANSWER_REQUEST )
|
||||
{
|
||||
UnitToUnitAnswerRequest utuar = (UnitToUnitAnswerRequest)message;
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.PAGE )
|
||||
.aliasList( mAliasList )
|
||||
.details( ( utuar.isEmergency() ? "EMERGENCY" : "" ) )
|
||||
.from( utuar.getSourceAddress() )
|
||||
.to( utuar.getTargetAddress() )
|
||||
.build() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a unit registration or deregistration message
|
||||
*/
|
||||
private void processRegistration( TSBKMessage message )
|
||||
{
|
||||
switch( message.getOpcode() )
|
||||
{
|
||||
case LOCATION_REGISTRATION_RESPONSE:
|
||||
LocationRegistrationResponse lrr =
|
||||
(LocationRegistrationResponse)message;
|
||||
|
||||
String addressPlusGroup = lrr.getTargetAddress() +
|
||||
lrr.getGroupAddress();
|
||||
|
||||
boolean updateEvent = false;
|
||||
|
||||
if( mRegistrations.containsKey( addressPlusGroup ) )
|
||||
{
|
||||
long timestamp = mRegistrations.get( addressPlusGroup );
|
||||
|
||||
updateEvent = ( System.currentTimeMillis() -
|
||||
timestamp ) > 300000; //5 minutes
|
||||
}
|
||||
else
|
||||
{
|
||||
updateEvent = true;
|
||||
}
|
||||
|
||||
mRegistrations.put( addressPlusGroup, System.currentTimeMillis() );
|
||||
|
||||
if( updateEvent )
|
||||
{
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.REGISTER )
|
||||
.aliasList( mAliasList )
|
||||
.details( "RESPONSE:" + lrr.getResponse().name() +
|
||||
" SITE: " + lrr.getRFSSID() + "-" +
|
||||
lrr.getSiteID() )
|
||||
.from( lrr.getTargetAddress() )
|
||||
.to( lrr.getGroupAddress() )
|
||||
.build() );
|
||||
}
|
||||
|
||||
/* Reset the deregistration variable */
|
||||
mLastDeRegistration = null;
|
||||
break;
|
||||
case UNIT_DEREGISTRATION_ACKNOWLEDGE:
|
||||
UnitDeregistrationAcknowledge udr =
|
||||
(UnitDeregistrationAcknowledge)message;
|
||||
|
||||
if( mLastDeRegistration != null &&
|
||||
mLastDeRegistration.contentEquals( udr.getSourceID() ) )
|
||||
{
|
||||
break; //Suppress duplicate event
|
||||
}
|
||||
|
||||
mLastDeRegistration = udr.getSourceID();
|
||||
|
||||
mCallEventModel.add(
|
||||
new P25CallEvent.Builder( CallEventType.DEREGISTER )
|
||||
.aliasList( mAliasList )
|
||||
.from( udr.getSourceID() )
|
||||
.build() );
|
||||
|
||||
List<String> keysToRemove = new ArrayList<String>();
|
||||
|
||||
/* Remove this radio from the registrations set */
|
||||
for( String key: mRegistrations.keySet() )
|
||||
{
|
||||
if( key.startsWith( udr.getSourceID() ) )
|
||||
{
|
||||
keysToRemove.add( key );
|
||||
}
|
||||
}
|
||||
|
||||
for( String key: keysToRemove )
|
||||
{
|
||||
mRegistrations.remove( key );
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSquelchState( SquelchState state )
|
||||
|
||||
@@ -19,6 +19,7 @@ package decode.p25;
|
||||
|
||||
import instrument.Instrumentable;
|
||||
import instrument.tap.Tap;
|
||||
import instrument.tap.stream.FloatTap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -31,6 +32,7 @@ import source.Source.SampleType;
|
||||
import alias.AliasList;
|
||||
import decode.Decoder;
|
||||
import decode.DecoderType;
|
||||
import dsp.agc.RealAutomaticGainControl;
|
||||
import dsp.filter.ComplexFIRFilter;
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window.WindowType;
|
||||
@@ -43,10 +45,17 @@ public class P25Decoder extends Decoder implements Instrumentable
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( P25Decoder.class );
|
||||
|
||||
/* Instrumentation Taps */
|
||||
private static final String INSTRUMENT_INPUT_TO_AGC = "Tap Point: Input to AGC";
|
||||
private static final String INSTRUMENT_AGC_TO_SYMBOL_FILTER = "Tap Point: AGC to Symbol Filter";
|
||||
private static final String INSTRUMENT_SYMBOL_FILTER_TO_SLICER = "Tap Point: Symbol Filter to Slicer";
|
||||
private List<Tap> mAvailableTaps;
|
||||
|
||||
private ComplexFIRFilter mBasebandFilter = new ComplexFIRFilter(
|
||||
FilterFactory.getLowPass( 48000, 5000, 31, WindowType.HAMMING ), 1.0 );
|
||||
|
||||
private FMDiscriminator mDemodulator = new FMDiscriminator( 1 );
|
||||
private RealAutomaticGainControl mAGC = new RealAutomaticGainControl();
|
||||
private C4FMSymbolFilter mSymbolFilter = new C4FMSymbolFilter();
|
||||
private C4FMSlicer mSlicer = new C4FMSlicer();
|
||||
private P25MessageFramer mNormalFramer;
|
||||
@@ -80,7 +89,8 @@ public class P25Decoder extends Decoder implements Instrumentable
|
||||
mDemodulator.setListener( getRealReceiver() );
|
||||
}
|
||||
|
||||
addRealSampleListener( mSymbolFilter );
|
||||
addRealSampleListener( mAGC );
|
||||
mAGC.setListener( mSymbolFilter );
|
||||
|
||||
mSymbolFilter.setListener( mSlicer );
|
||||
|
||||
@@ -108,17 +118,65 @@ public class P25Decoder extends Decoder implements Instrumentable
|
||||
@Override
|
||||
public List<Tap> getTaps()
|
||||
{
|
||||
return new ArrayList<Tap>();
|
||||
if( mAvailableTaps == null )
|
||||
{
|
||||
mAvailableTaps = new ArrayList<Tap>();
|
||||
|
||||
mAvailableTaps.add( new FloatTap( INSTRUMENT_INPUT_TO_AGC, 0, 1.0f ) );
|
||||
mAvailableTaps.add( new FloatTap( INSTRUMENT_AGC_TO_SYMBOL_FILTER, 0, 1.0f ) );
|
||||
mAvailableTaps.add( new FloatTap( INSTRUMENT_SYMBOL_FILTER_TO_SLICER, 0, 0.1f ) );
|
||||
|
||||
mAvailableTaps.addAll( mSymbolFilter.getTaps() );
|
||||
}
|
||||
|
||||
return mAvailableTaps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTap( Tap tap )
|
||||
{
|
||||
mSymbolFilter.addTap( tap );
|
||||
|
||||
switch( tap.getName() )
|
||||
{
|
||||
case INSTRUMENT_INPUT_TO_AGC:
|
||||
FloatTap inputAGC = (FloatTap)tap;
|
||||
removeRealListener( mAGC );
|
||||
addRealSampleListener( inputAGC );
|
||||
inputAGC.setListener( mAGC );
|
||||
break;
|
||||
case INSTRUMENT_AGC_TO_SYMBOL_FILTER:
|
||||
FloatTap agcSymbol = (FloatTap)tap;
|
||||
mAGC.setListener( agcSymbol );
|
||||
agcSymbol.setListener( mSymbolFilter );
|
||||
break;
|
||||
case INSTRUMENT_SYMBOL_FILTER_TO_SLICER:
|
||||
FloatTap symbolSlicer = (FloatTap)tap;
|
||||
mSymbolFilter.setListener( symbolSlicer );
|
||||
symbolSlicer.setListener( mSlicer );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTap( Tap tap )
|
||||
{
|
||||
mSymbolFilter.removeTap( tap );
|
||||
|
||||
switch( tap.getName() )
|
||||
{
|
||||
case INSTRUMENT_INPUT_TO_AGC:
|
||||
FloatTap inputAGC = (FloatTap)tap;
|
||||
removeRealListener( inputAGC );
|
||||
addRealSampleListener( mAGC );
|
||||
break;
|
||||
case INSTRUMENT_AGC_TO_SYMBOL_FILTER:
|
||||
mAGC.setListener( mSymbolFilter );
|
||||
break;
|
||||
case INSTRUMENT_SYMBOL_FILTER_TO_SLICER:
|
||||
mSymbolFilter.setListener( mSlicer );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package decode.p25.message.tsbk;
|
||||
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import bits.BitSetBuffer;
|
||||
import decode.p25.message.tsbk.osp.control.IdentifierUpdate;
|
||||
import decode.p25.message.tsbk.osp.control.IdentifierUpdateReceiver;
|
||||
import decode.p25.reference.DataUnitID;
|
||||
|
||||
public abstract class GroupMultiChannelGrant extends ChannelGrant
|
||||
implements IdentifierUpdateReceiver
|
||||
{
|
||||
public static final int[] CHANNEL_ID_1 = { 80,81,82,83 };
|
||||
public static final int[] CHANNEL_NUMBER_1 = { 84,85,86,87,
|
||||
@@ -17,6 +19,9 @@ public abstract class GroupMultiChannelGrant extends ChannelGrant
|
||||
112,113,114,115,116,117,118,119 };
|
||||
public static final int[] GROUP_ADDRESS_2 = { 120,121,122,123,124,125,126,
|
||||
127,128,129,130,131,132,133,134,135 };
|
||||
|
||||
private IdentifierUpdate mIdentifierUpdate1;
|
||||
private IdentifierUpdate mIdentifierUpdate2;
|
||||
|
||||
public GroupMultiChannelGrant( BitSetBuffer message,
|
||||
DataUnitID duid,
|
||||
@@ -37,11 +42,14 @@ public abstract class GroupMultiChannelGrant extends ChannelGrant
|
||||
sb.append( " GRP1:" );
|
||||
sb.append( getGroupAddress1() );
|
||||
|
||||
sb.append( " CHAN2:" );
|
||||
sb.append( getChannelID2() + "/" + getChannelNumber2() );
|
||||
|
||||
sb.append( " GRP2:" );
|
||||
sb.append( getGroupAddress2() );
|
||||
if( hasChannelNumber2() )
|
||||
{
|
||||
sb.append( " CHAN2:" );
|
||||
sb.append( getChannelID2() + "/" + getChannelNumber2() );
|
||||
|
||||
sb.append( " GRP2:" );
|
||||
sb.append( getGroupAddress2() );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -76,6 +84,11 @@ public abstract class GroupMultiChannelGrant extends ChannelGrant
|
||||
return mMessage.getHex( GROUP_ADDRESS_2, 4 );
|
||||
}
|
||||
|
||||
public boolean hasChannelNumber2()
|
||||
{
|
||||
return mMessage.getInt( GROUP_ADDRESS_2 ) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFromID()
|
||||
{
|
||||
@@ -87,4 +100,59 @@ public abstract class GroupMultiChannelGrant extends ChannelGrant
|
||||
{
|
||||
return getGroupAddress2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifierMessage( int identifier, IdentifierUpdate message )
|
||||
{
|
||||
if( identifier == getChannelID1() )
|
||||
{
|
||||
mIdentifierUpdate1 = message;
|
||||
}
|
||||
|
||||
if( hasChannelNumber2() && identifier == getChannelID2() )
|
||||
{
|
||||
mIdentifierUpdate2 = message;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getIdentifiers()
|
||||
{
|
||||
int[] identifiers;
|
||||
|
||||
if( hasChannelNumber2() )
|
||||
{
|
||||
identifiers = new int[ 2 ];
|
||||
identifiers[ 0 ] = getChannelID1();
|
||||
identifiers[ 1 ] = getChannelID2();
|
||||
}
|
||||
else
|
||||
{
|
||||
identifiers = new int[ 1 ];
|
||||
identifiers[ 0 ] = getChannelID1();
|
||||
}
|
||||
|
||||
return identifiers;
|
||||
}
|
||||
|
||||
public long getDownlinkFrequency1()
|
||||
{
|
||||
return calculateDownlink( mIdentifierUpdate1, getChannel() );
|
||||
}
|
||||
|
||||
public long getUplinkFrequency1()
|
||||
{
|
||||
return calculateUplink( mIdentifierUpdate1, getChannel() );
|
||||
}
|
||||
|
||||
public long getDownlinkFrequency2()
|
||||
{
|
||||
return calculateDownlink( mIdentifierUpdate2, getChannel() );
|
||||
}
|
||||
|
||||
public long getUplinkFrequency2()
|
||||
{
|
||||
return calculateUplink( mIdentifierUpdate2, getChannel() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,15 +36,10 @@ public class TSBKMessage extends P25Message
|
||||
public TSBKMessage( BitSetBuffer message, DataUnitID duid, AliasList aliasList )
|
||||
{
|
||||
super( message, duid, aliasList );
|
||||
|
||||
checkCRC();
|
||||
}
|
||||
|
||||
protected void checkCRC()
|
||||
{
|
||||
mCRC = new CRC[ 1 ];
|
||||
|
||||
mCRC[ 0 ] = CRCP25.correctCCITT80( mMessage, MESSAGE_START, CRC_START );
|
||||
/* Since CRC is checked before construction, mark it as passed */
|
||||
mCRC = new CRC[ 1 ];
|
||||
mCRC[ 0 ] = CRC.PASSED;
|
||||
}
|
||||
|
||||
public boolean isLastBlock()
|
||||
|
||||
@@ -18,6 +18,6 @@ public class GroupVoiceChannelGrantUpdate extends GroupMultiChannelGrant
|
||||
@Override
|
||||
public String getEventType()
|
||||
{
|
||||
return Opcode.GROUP_VOICE_CHANNEL_GRANT.getDescription();
|
||||
return Opcode.GROUP_VOICE_CHANNEL_GRANT_UPDATE.getDescription();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package decode.p25.message.tsbk.osp.voice;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import bits.BitSetBuffer;
|
||||
import decode.p25.message.tsbk.TSBKMessage;
|
||||
@@ -34,6 +33,12 @@ public class TelephoneInterconnectAnswerRequest extends TSBKMessage
|
||||
super( message, duid, aliasList );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventType()
|
||||
{
|
||||
return Opcode.TELEPHONE_INTERCONNECT_ANSWER_REQUEST.getDescription();
|
||||
}
|
||||
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -72,12 +77,6 @@ public class TelephoneInterconnectAnswerRequest extends TSBKMessage
|
||||
return mMessage.getHex( TARGET_ADDRESS, 6 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventType()
|
||||
{
|
||||
return Opcode.TELEPHONE_INTERCONNECT_ANSWER_REQUEST.getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToID()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user