mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
* Resolves #701 Updates P25P2 Tone metadata handling and P25P2 channel state management.
This commit is contained in:
@@ -572,7 +572,7 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
|
||||
|
||||
if(type == null)
|
||||
{
|
||||
mLog.debug("Unrecognized opcode for determining decode event type: " + opcode.name());
|
||||
mLog.error("Unrecognized opcode for determining decode event type: " + opcode.name());
|
||||
type = DecodeEventType.CALL;
|
||||
}
|
||||
|
||||
@@ -697,7 +697,7 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
|
||||
//Issue a disable request for each traffic channel
|
||||
for(Channel channel: channels)
|
||||
{
|
||||
mLog.debug("Stopping traffic channel: " + channel);
|
||||
mLog.info("Stopping traffic channel: " + channel);
|
||||
broadcast(new ChannelEvent(channel, Event.REQUEST_DISABLE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
package io.github.dsheirer.module.decode.p25.audio;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.audio.codec.mbe.AmbeAudioModule;
|
||||
import io.github.dsheirer.audio.squelch.SquelchState;
|
||||
@@ -27,9 +28,7 @@ import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.IdentifierUpdateNotification;
|
||||
import io.github.dsheirer.identifier.IdentifierUpdateProvider;
|
||||
import io.github.dsheirer.identifier.tone.P25CallProgressIdentifier;
|
||||
import io.github.dsheirer.identifier.tone.P25DtmfIdentifier;
|
||||
import io.github.dsheirer.identifier.tone.P25KnoxIdentifier;
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.tone.P25ToneIdentifier;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.EncryptionSynchronizationSequence;
|
||||
@@ -51,17 +50,9 @@ public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdat
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25P2AudioModule.class);
|
||||
|
||||
private static final String METADATA_TYPE_DTMF = "DTMF";
|
||||
private static final String METADATA_TYPE_KNOX = "KNOX";
|
||||
private static final String METADATA_TYPE_TONE = "TONE";
|
||||
private static final String METADATA_TYPE_CALL_PROGRESS = "CALL PROGRESS";
|
||||
|
||||
private Listener<IdentifierUpdateNotification> mIdentifierUpdateNotificationListener;
|
||||
private SquelchStateListener mSquelchStateListener = new SquelchStateListener();
|
||||
private MetadataProcessor mDtmfMetadataProcessor;
|
||||
private MetadataProcessor mKnoxMetadataProcessor;
|
||||
private MetadataProcessor mToneMetadataProcessor;
|
||||
private MetadataProcessor mCallProcessMetadataProcessor;
|
||||
private ToneMetadataProcessor mToneMetadataProcessor = new ToneMetadataProcessor();
|
||||
private int mTimeslot;
|
||||
private Queue<AbstractVoiceTimeslot> mQueuedAudioTimeslots = new ArrayDeque<>();
|
||||
private boolean mEncryptedCallStateEstablished = false;
|
||||
@@ -92,10 +83,10 @@ public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdat
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
mCallProcessMetadataProcessor = null;
|
||||
mDtmfMetadataProcessor = null;
|
||||
mKnoxMetadataProcessor = null;
|
||||
mToneMetadataProcessor = null;
|
||||
//Explicitly clear FROM identifiers to ensure previous call TONE identifiers are cleared.
|
||||
mIdentifierCollection.remove(Role.FROM);
|
||||
|
||||
mToneMetadataProcessor.reset();
|
||||
mQueuedAudioTimeslots.clear();
|
||||
|
||||
//Reset encrypted call handling flags
|
||||
@@ -179,107 +170,44 @@ public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdat
|
||||
{
|
||||
byte[] voiceFrameBytes = voiceFrame.getBytes();
|
||||
|
||||
IAudioWithMetadata audioWithMetadata = getAudioCodec().getAudioWithMetadata(voiceFrameBytes);
|
||||
processMetadata(audioWithMetadata);
|
||||
addAudio(audioWithMetadata.getAudio());
|
||||
try
|
||||
{
|
||||
IAudioWithMetadata audioWithMetadata = getAudioCodec().getAudioWithMetadata(voiceFrameBytes);
|
||||
addAudio(audioWithMetadata.getAudio());
|
||||
processMetadata(audioWithMetadata);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("Error synthesizing AMBE audio - continuing [" + e.getLocalizedMessage() + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes optional metadata that can be included with decoded audio (ie dtmf, tones, knox, etc.)
|
||||
* Processes optional metadata that can be included with decoded audio (ie dtmf, tones, knox, etc.) so that the
|
||||
* tone metadata can be converted into a FROM identifier and included with any call segment.
|
||||
*/
|
||||
private void processMetadata(IAudioWithMetadata audioWithMetadata)
|
||||
{
|
||||
if(mIdentifierUpdateNotificationListener != null)
|
||||
if(audioWithMetadata.hasMetadata() && mIdentifierUpdateNotificationListener != null)
|
||||
{
|
||||
if(audioWithMetadata.hasMetadata())
|
||||
for(Map.Entry<String,String> entry: audioWithMetadata.getMetadata().entrySet())
|
||||
{
|
||||
Map<String,String> metadata = audioWithMetadata.getMetadata();
|
||||
//Each metadata map entry contains a tone-type (key) and tone (value)
|
||||
Identifier metadataIdentifier = mToneMetadataProcessor.process(entry.getKey(), entry.getValue());
|
||||
|
||||
if(metadata.containsKey(METADATA_TYPE_DTMF))
|
||||
if(metadataIdentifier != null)
|
||||
{
|
||||
String dtmf = metadata.get(METADATA_TYPE_DTMF);
|
||||
|
||||
if(dtmf != null)
|
||||
{
|
||||
if(mDtmfMetadataProcessor == null)
|
||||
{
|
||||
mDtmfMetadataProcessor = new MetadataProcessor();
|
||||
}
|
||||
|
||||
List<String> dtmfTones = mDtmfMetadataProcessor.process(dtmf);
|
||||
broadcast(P25DtmfIdentifier.create(dtmfTones));
|
||||
}
|
||||
}
|
||||
else if(metadata.containsKey(METADATA_TYPE_KNOX))
|
||||
{
|
||||
String knox = metadata.get(METADATA_TYPE_KNOX);
|
||||
|
||||
if(knox != null)
|
||||
{
|
||||
if(mKnoxMetadataProcessor == null)
|
||||
{
|
||||
mKnoxMetadataProcessor = new MetadataProcessor();
|
||||
}
|
||||
|
||||
List<String> knoxTones = mKnoxMetadataProcessor.process(knox);
|
||||
broadcast(P25KnoxIdentifier.create(knoxTones));
|
||||
}
|
||||
}
|
||||
else if(metadata.containsKey(METADATA_TYPE_TONE))
|
||||
{
|
||||
String tone = metadata.get(METADATA_TYPE_TONE);
|
||||
|
||||
if(tone != null)
|
||||
{
|
||||
if(mToneMetadataProcessor == null)
|
||||
{
|
||||
mToneMetadataProcessor = new MetadataProcessor();
|
||||
}
|
||||
|
||||
List<String> tones = mToneMetadataProcessor.process(tone);
|
||||
broadcast(P25ToneIdentifier.create(tones));
|
||||
}
|
||||
}
|
||||
else if(metadata.containsKey(METADATA_TYPE_CALL_PROGRESS))
|
||||
{
|
||||
String callProgressTone = metadata.get(METADATA_TYPE_CALL_PROGRESS);
|
||||
|
||||
if(callProgressTone != null)
|
||||
{
|
||||
if(mCallProcessMetadataProcessor == null)
|
||||
{
|
||||
mCallProcessMetadataProcessor = new MetadataProcessor();
|
||||
}
|
||||
|
||||
List<String> tones = mCallProcessMetadataProcessor.process(callProgressTone);
|
||||
broadcast(P25CallProgressIdentifier.create(tones));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mDtmfMetadataProcessor != null)
|
||||
{
|
||||
mDtmfMetadataProcessor.noMetadata();
|
||||
}
|
||||
if(mKnoxMetadataProcessor != null)
|
||||
{
|
||||
mKnoxMetadataProcessor.noMetadata();
|
||||
}
|
||||
if(mCallProcessMetadataProcessor != null)
|
||||
{
|
||||
mCallProcessMetadataProcessor.noMetadata();
|
||||
}
|
||||
if(mToneMetadataProcessor != null)
|
||||
{
|
||||
mToneMetadataProcessor.noMetadata();
|
||||
broadcast(metadataIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the identifier to a registered listener
|
||||
*/
|
||||
private void broadcast(Identifier identifier)
|
||||
{
|
||||
if(mIdentifierUpdateNotificationListener != null)
|
||||
@@ -289,12 +217,18 @@ public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdat
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listener to receive identifier updates
|
||||
*/
|
||||
@Override
|
||||
public void setIdentifierUpdateListener(Listener<IdentifierUpdateNotification> listener)
|
||||
{
|
||||
mIdentifierUpdateNotificationListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a listener from receiving identifier updates
|
||||
*/
|
||||
@Override
|
||||
public void removeIdentifierUpdateListener()
|
||||
{
|
||||
@@ -302,40 +236,124 @@ public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdat
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes metadata string values to provide a de-duplicated list of metadata values.
|
||||
*
|
||||
* This is necessary for metadata such as DTMF where a tone can span multiple 20ms voice frames but is intended
|
||||
* to be represented as a single tone. An empty (no-metadata) frame causes the repeat checker to stop and allow
|
||||
* the next metadata value to be added to the list.
|
||||
* Process AMBE audio frame tone metadata. Tracks the count of sequential frames containing tone metadata to
|
||||
* provide a list of each unique tone and a time duration (milliseconds) for the tone. Tones are concatenated into
|
||||
* a comma separated list and included as call segment metadata.
|
||||
*/
|
||||
public class MetadataProcessor
|
||||
public class ToneMetadataProcessor
|
||||
{
|
||||
private List<String> mValues = new ArrayList<>();
|
||||
private String mLastInput;
|
||||
private List<ToneMetadata> mToneMetadata = new ArrayList<>();
|
||||
|
||||
public List<String> process(String value)
|
||||
/**
|
||||
* Resets or clears any accumulated call tone metadata to prepare for the next call.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
if(value != null)
|
||||
{
|
||||
if(mLastInput != null && mLastInput.equalsIgnoreCase(value))
|
||||
{
|
||||
//Suppress the repeat and return the current value
|
||||
return mValues;
|
||||
}
|
||||
else
|
||||
{
|
||||
mLastInput = value;
|
||||
mValues.add(value);
|
||||
return mValues;
|
||||
}
|
||||
}
|
||||
|
||||
return mValues;
|
||||
mToneMetadata.clear();
|
||||
}
|
||||
|
||||
public void noMetadata()
|
||||
/**
|
||||
* Process the tone metadata
|
||||
* @param type of tone
|
||||
* @param value of tone
|
||||
* @return an identifier with the accumulated tone metadata set
|
||||
*/
|
||||
public Identifier process(String type, String value)
|
||||
{
|
||||
mLastInput = null;
|
||||
if(type == null || value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ToneMetadata toneMetadata = (mToneMetadata.size() > 0 ? mToneMetadata.get(mToneMetadata.size() - 1) : null);
|
||||
|
||||
if(toneMetadata == null || !toneMetadata.matches(type, value))
|
||||
{
|
||||
toneMetadata = new ToneMetadata(type, value);
|
||||
mToneMetadata.add(toneMetadata);
|
||||
}
|
||||
|
||||
toneMetadata.incrementCount();
|
||||
|
||||
return P25ToneIdentifier.create(Joiner.on(",").join(mToneMetadata));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata about the tone type being transmitted and the duration.
|
||||
*
|
||||
* Note: each AMBE frame is 20 milliseconds in duration, so total duration is the count of 20 ms tone frames
|
||||
* of the same metadata type.
|
||||
*/
|
||||
public class ToneMetadata
|
||||
{
|
||||
private String mType;
|
||||
private String mValue;
|
||||
private int mCount;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param type of tone
|
||||
* @param value of the tone
|
||||
*/
|
||||
public ToneMetadata(String type, String value)
|
||||
{
|
||||
mType = type;
|
||||
mValue = value;
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this tone metadata matches the tone metadata represented by the arguments
|
||||
* @param type of tone
|
||||
* @param value of tone
|
||||
* @return true if they match
|
||||
*/
|
||||
public boolean matches(String type, String value)
|
||||
{
|
||||
return type != null && value != null && type.matches(mType) && value.matches(mValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of tone
|
||||
*/
|
||||
public String getType()
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value of tone
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of times this tone has occurred sequentially
|
||||
*/
|
||||
public int getCount()
|
||||
{
|
||||
return mCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the count of the number of sequential frames that contained the tone
|
||||
*/
|
||||
public void incrementCount()
|
||||
{
|
||||
mCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(mType);
|
||||
sb.append(" ").append(mValue);
|
||||
sb.append(" (").append(mCount * 20).append("ms)");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,5 +377,4 @@ public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ import io.github.dsheirer.module.decode.event.DecodeEventType;
|
||||
import io.github.dsheirer.module.decode.p25.P25DecodeEvent;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.EncryptionSynchronizationSequence;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacMessage;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacPduType;
|
||||
@@ -102,6 +103,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
private PatchGroupManager mPatchGroupManager = new PatchGroupManager();
|
||||
private P25P2NetworkConfigurationMonitor mNetworkConfigurationMonitor = new P25P2NetworkConfigurationMonitor();
|
||||
private DecodeEvent mCurrentCallEvent;
|
||||
private int mEndPttOnFacchCounter = 0;
|
||||
|
||||
/**
|
||||
* Constructs an APCO-25 decoder state for a traffic channel.
|
||||
@@ -138,7 +140,8 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
protected void resetState()
|
||||
{
|
||||
super.resetState();
|
||||
closeCurrentCallEvent(System.currentTimeMillis(), true);
|
||||
closeCurrentCallEvent(System.currentTimeMillis(), true, MacPduType.MAC_3_IDLE);
|
||||
mEndPttOnFacchCounter = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,28 +154,68 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
{
|
||||
if(message instanceof MacMessage)
|
||||
{
|
||||
processMacMessage((MacMessage)message);
|
||||
MacMessage macMessage = (MacMessage)message;
|
||||
processMacMessage(macMessage);
|
||||
|
||||
MacPduType macPduType = macMessage.getMacPduType();
|
||||
|
||||
//Ignore End PTT - this is handled in the processMacMessage() method
|
||||
if(macPduType != MacPduType.MAC_2_END_PTT)
|
||||
{
|
||||
mEndPttOnFacchCounter = 0;
|
||||
continueState(getStateFromPduType(macPduType));
|
||||
}
|
||||
|
||||
if(macPduType == MacPduType.MAC_3_IDLE)
|
||||
{
|
||||
closeCurrentCallEvent(message.getTimestamp(), true, macPduType);
|
||||
}
|
||||
}
|
||||
else if(message instanceof AbstractVoiceTimeslot)
|
||||
{
|
||||
if(isEncrypted())
|
||||
if(mCurrentCallEvent != null)
|
||||
{
|
||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.ENCRYPTED, getTimeslot()));
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL, getTimeslot()));
|
||||
if(isEncrypted())
|
||||
{
|
||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.ENCRYPTED, getTimeslot()));
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL, getTimeslot()));
|
||||
}
|
||||
}
|
||||
|
||||
updateCurrentCall(null, null, message.getTimestamp());
|
||||
}
|
||||
else if(message instanceof EncryptionSynchronizationSequence)
|
||||
{
|
||||
//We don't send any state events for this message since it can only occur in conjunction with
|
||||
//an audio frame that already sends the call state event
|
||||
getIdentifierCollection().update(message.getIdentifiers());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channel state according to the PDU type
|
||||
*/
|
||||
private static State getStateFromPduType(MacPduType macPduType)
|
||||
{
|
||||
switch(macPduType)
|
||||
{
|
||||
case MAC_1_PTT:
|
||||
return State.CALL;
|
||||
case MAC_2_END_PTT:
|
||||
return State.TEARDOWN;
|
||||
case MAC_4_ACTIVE:
|
||||
case MAC_6_HANGTIME:
|
||||
return State.ACTIVE;
|
||||
case MAC_3_IDLE:
|
||||
default:
|
||||
return State.IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the current channel to the local identifier collection which will cause it to be broadcast to all of the
|
||||
* other listeners and will allow both timeslots on this channel to receive it and update accordingly.
|
||||
@@ -215,30 +258,67 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
{
|
||||
//Add the set of identifiers before we close out the call event to ensure they're captured in
|
||||
//the closing event.
|
||||
for(Identifier identifier : mac.getIdentifiers())
|
||||
if(mCurrentCallEvent != null)
|
||||
{
|
||||
if(identifier.getRole() == Role.FROM && identifier instanceof APCO25RadioIdentifier)
|
||||
for(Identifier identifier : mac.getIdentifiers())
|
||||
{
|
||||
int value = ((APCO25RadioIdentifier)identifier).getValue();
|
||||
|
||||
if(value == SYSTEM_CONTROLLER)
|
||||
if(identifier.getRole() == Role.FROM)
|
||||
{
|
||||
//ignore so we don't overwrite the real from radio identifier
|
||||
if(identifier instanceof APCO25RadioIdentifier)
|
||||
{
|
||||
int value = ((APCO25RadioIdentifier)identifier).getValue();
|
||||
|
||||
//Group call End PTT uses a FROM value of 0xFFFFFF - don't overwrite the correct id
|
||||
if(value != SYSTEM_CONTROLLER)
|
||||
{
|
||||
getIdentifierCollection().update(mPatchGroupManager.update(identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(identifier.getRole() == Role.TO)
|
||||
{
|
||||
if(identifier instanceof APCO25Talkgroup)
|
||||
{
|
||||
int value = ((APCO25Talkgroup)identifier).getValue();
|
||||
|
||||
//Individual call End PTT uses a TO value of 0 - don't overwrite the correct id
|
||||
if(value != 0)
|
||||
{
|
||||
getIdentifierCollection().update(mPatchGroupManager.update(identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Add to the identifier collection after filtering through the patch group manager
|
||||
getIdentifierCollection().update(mPatchGroupManager.update(identifier));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Add to the identifier collection after filtering through the patch group manager
|
||||
getIdentifierCollection().update(mPatchGroupManager.update(identifier));
|
||||
}
|
||||
}
|
||||
|
||||
closeCurrentCallEvent(message.getTimestamp(), true);
|
||||
if(message.getDataUnitID().isFACCH())
|
||||
{
|
||||
mEndPttOnFacchCounter++;
|
||||
|
||||
//FNE sending 2 or more End PTT in FACCH timeslots indicates a channel teardown event.
|
||||
if(mEndPttOnFacchCounter > 1)
|
||||
{
|
||||
if(mChannelType == ChannelType.TRAFFIC)
|
||||
{
|
||||
closeCurrentCallEvent(message.getTimestamp(), true, MacPduType.MAC_2_END_PTT);
|
||||
//Don't send a continue state here ... the close() method will send the TEARDOWN state
|
||||
}
|
||||
//Otherwise the channel state is set to ACTIVE in anticipation of further call activity
|
||||
else
|
||||
{
|
||||
closeCurrentCallEvent(message.getTimestamp(), true, MacPduType.MAC_4_ACTIVE);
|
||||
continueState(State.RESET);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
closeCurrentCallEvent(message.getTimestamp(), true, MacPduType.MAC_4_ACTIVE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TDMA_0_NULL_INFORMATION_MESSAGE:
|
||||
@@ -246,15 +326,13 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
|
||||
if(type == MacPduType.MAC_3_IDLE || type == MacPduType.MAC_6_HANGTIME)
|
||||
{
|
||||
closeCurrentCallEvent(message.getTimestamp(), true);
|
||||
closeCurrentCallEvent(message.getTimestamp(), true, type);
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case TDMA_1_GROUP_VOICE_CHANNEL_USER_ABBREVIATED:
|
||||
if(message.getMacPduType() == MacPduType.MAC_6_HANGTIME)
|
||||
{
|
||||
closeCurrentCallEvent(message.getTimestamp(), false);
|
||||
getIdentifierCollection().remove(Role.FROM);
|
||||
closeCurrentCallEvent(message.getTimestamp(), false, MacPduType.MAC_6_HANGTIME);
|
||||
|
||||
for(Identifier identifier : mac.getIdentifiers())
|
||||
{
|
||||
@@ -291,8 +369,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
case TDMA_33_GROUP_VOICE_CHANNEL_USER_EXTENDED:
|
||||
if(message.getMacPduType() == MacPduType.MAC_6_HANGTIME)
|
||||
{
|
||||
closeCurrentCallEvent(message.getTimestamp(), false);
|
||||
getIdentifierCollection().remove(Role.FROM);
|
||||
closeCurrentCallEvent(message.getTimestamp(), false, MacPduType.MAC_6_HANGTIME);
|
||||
|
||||
for(Identifier identifier : mac.getIdentifiers())
|
||||
{
|
||||
@@ -329,8 +406,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
case TDMA_2_UNIT_TO_UNIT_VOICE_CHANNEL_USER:
|
||||
if(message.getMacPduType() == MacPduType.MAC_6_HANGTIME)
|
||||
{
|
||||
closeCurrentCallEvent(message.getTimestamp(), false);
|
||||
getIdentifierCollection().remove(Role.FROM);
|
||||
closeCurrentCallEvent(message.getTimestamp(), false, MacPduType.MAC_6_HANGTIME);
|
||||
|
||||
for(Identifier identifier : mac.getIdentifiers())
|
||||
{
|
||||
@@ -367,8 +443,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
case TDMA_34_UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED:
|
||||
if(message.getMacPduType() == MacPduType.MAC_6_HANGTIME)
|
||||
{
|
||||
closeCurrentCallEvent(message.getTimestamp(), false);
|
||||
getIdentifierCollection().remove(Role.FROM);
|
||||
closeCurrentCallEvent(message.getTimestamp(), false, MacPduType.MAC_6_HANGTIME);
|
||||
|
||||
for(Identifier identifier : mac.getIdentifiers())
|
||||
{
|
||||
@@ -405,8 +480,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
case TDMA_3_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER:
|
||||
if(message.getMacPduType() == MacPduType.MAC_6_HANGTIME)
|
||||
{
|
||||
closeCurrentCallEvent(message.getTimestamp(), false);
|
||||
getIdentifierCollection().remove(Role.FROM);
|
||||
closeCurrentCallEvent(message.getTimestamp(), false, MacPduType.MAC_6_HANGTIME);
|
||||
|
||||
for(Identifier identifier : mac.getIdentifiers())
|
||||
{
|
||||
@@ -439,7 +513,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
}
|
||||
}
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case TDMA_5_GROUP_VOICE_CHANNEL_GRANT_UPDATE_MULTIPLE:
|
||||
if(getCurrentChannel() == null && mac instanceof GroupVoiceChannelGrantUpdateMultiple)
|
||||
@@ -461,7 +534,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
broadcastCurrentChannel(gvcgum.getChannelC());
|
||||
}
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case TDMA_37_GROUP_VOICE_CHANNEL_GRANT_UPDATE_MULTIPLE_EXPLICIT:
|
||||
if(getCurrentChannel() == null && mac instanceof GroupVoiceChannelGrantUpdateMultipleExplicit)
|
||||
@@ -478,7 +550,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
broadcastCurrentChannel(gvcgume.getChannelB());
|
||||
}
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_64_GROUP_VOICE_CHANNEL_GRANT_ABBREVIATED:
|
||||
if(getCurrentChannel() == null && mac instanceof GroupVoiceChannelGrantAbbreviated)
|
||||
@@ -490,7 +561,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
broadcastCurrentChannel(gvcga.getChannel());
|
||||
}
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_66_GROUP_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
if(getCurrentChannel() == null && mac instanceof GroupVoiceChannelGrantUpdate)
|
||||
@@ -507,7 +577,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
broadcastCurrentChannel(gvcgu.getChannelB());
|
||||
}
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_70_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_ABBREVIATED:
|
||||
if(getCurrentChannel() == null && mac instanceof UnitToUnitVoiceChannelGrantAbbreviated)
|
||||
@@ -519,7 +588,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
broadcastCurrentChannel(uuvcga.getChannel());
|
||||
}
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_195_GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
|
||||
if(getCurrentChannel() == null && mac instanceof GroupVoiceChannelGrantUpdateExplicit)
|
||||
@@ -531,7 +599,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
broadcastCurrentChannel(gvcgue.getChannel());
|
||||
}
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_198_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_EXTENDED:
|
||||
if(getCurrentChannel() == null && mac instanceof UnitToUnitVoiceChannelGrantUpdateExtended)
|
||||
@@ -543,7 +610,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
broadcastCurrentChannel(uuvcgue.getChannel());
|
||||
}
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case TDMA_17_INDIRECT_GROUP_PAGING:
|
||||
MutableIdentifierCollection icGroupPaging = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
@@ -556,7 +622,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.details("GROUP PAGE")
|
||||
.identifiers(icGroupPaging)
|
||||
.build());
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case TDMA_18_INDIVIDUAL_PAGING_MESSAGE_WITH_PRIORITY:
|
||||
if(mac instanceof IndividualPagingMessage)
|
||||
@@ -575,7 +640,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icIndividualPaging)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case TDMA_48_POWER_CONTROL_SIGNAL_QUALITY:
|
||||
if(mac instanceof PowerControlSignalQuality)
|
||||
@@ -593,7 +657,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icPowerControl)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case TDMA_49_MAC_RELEASE:
|
||||
if(mac instanceof MacRelease)
|
||||
@@ -604,7 +667,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
icMacRelease.remove(IdentifierClass.USER);
|
||||
icMacRelease.update(mac.getIdentifiers());
|
||||
|
||||
closeCurrentCallEvent(message.getTimestamp(), true);
|
||||
closeCurrentCallEvent(message.getTimestamp(), true, message.getMacPduType());
|
||||
|
||||
broadcast(P25DecodeEvent.builder(message.getTimestamp())
|
||||
.channel(getCurrentChannel())
|
||||
@@ -630,7 +693,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icMacRelease)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_68_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_ABBREVIATED:
|
||||
if(mac instanceof UnitToUnitVoiceChannelGrantAbbreviated)
|
||||
@@ -647,7 +709,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icGrant)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_69_UNIT_TO_UNIT_ANSWER_REQUEST_ABBREVIATED:
|
||||
if(mac instanceof UnitToUnitAnswerRequestAbbreviated)
|
||||
@@ -664,7 +725,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icRequest)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_74_TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
|
||||
if(mac instanceof TelephoneInterconnectAnswerRequest)
|
||||
@@ -681,7 +741,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icRequest)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_76_RADIO_UNIT_MONITOR_COMMAND_ABBREVIATED:
|
||||
if(mac instanceof RadioUnitMonitorCommand)
|
||||
@@ -699,7 +758,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icRequest)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_84_SNDCP_DATA_CHANNEL_GRANT:
|
||||
if(mac instanceof SNDCPDataChannelGrant)
|
||||
@@ -716,7 +774,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icGrant)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_85_SNDCP_DATA_PAGE_REQUEST:
|
||||
if(mac instanceof SNDCPDataPageRequest)
|
||||
@@ -733,7 +790,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icPage)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_88_STATUS_UPDATE_ABBREVIATED:
|
||||
if(mac instanceof StatusUpdateAbbreviated)
|
||||
@@ -750,7 +806,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icStatusUpdate)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_90_STATUS_QUERY_ABBREVIATED:
|
||||
if(mac instanceof StatusQueryAbbreviated)
|
||||
@@ -766,7 +821,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icStatusUpdate)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_92_MESSAGE_UPDATE_ABBREVIATED:
|
||||
if(mac instanceof MessageUpdateAbbreviated)
|
||||
@@ -783,7 +837,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icStatusUpdate)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_94_RADIO_UNIT_MONITOR_COMMAND_ENHANCED:
|
||||
if(mac instanceof RadioUnitMonitorCommandEnhanced)
|
||||
@@ -802,7 +855,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icRequest)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_95_CALL_ALERT_ABBREVIATED:
|
||||
MutableIdentifierCollection icCallAlert = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
@@ -814,7 +866,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.eventDescription(DecodeEventType.CALL_ALERT.toString())
|
||||
.identifiers(icCallAlert)
|
||||
.build());
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_96_ACK_RESPONSE:
|
||||
if(mac instanceof AcknowledgeResponse)
|
||||
@@ -831,7 +882,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icAckResponse)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_97_QUEUED_RESPONSE:
|
||||
if(mac instanceof QueuedResponse)
|
||||
@@ -850,7 +900,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icQueuedResponse)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_100_EXTENDED_FUNCTION_COMMAND_ABBREVIATED:
|
||||
if(mac instanceof ExtendedFunctionCommand)
|
||||
@@ -868,7 +917,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icExtendedFunction)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_103_DENY_RESPONSE:
|
||||
if(mac instanceof DenyResponse)
|
||||
@@ -885,7 +933,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icDenyResponse)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_106_GROUP_AFFILIATION_QUERY_ABBREVIATED:
|
||||
MutableIdentifierCollection icGroupAffiliationQuery = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
@@ -898,7 +945,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.details("GROUP AFFILIATION")
|
||||
.identifiers(icGroupAffiliationQuery)
|
||||
.build());
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_109_UNIT_REGISTRATION_COMMAND_ABBREVIATED:
|
||||
MutableIdentifierCollection icUnitRegisterCommand = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
@@ -911,7 +957,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.details("UNIT REGISTRATION")
|
||||
.identifiers(icUnitRegisterCommand)
|
||||
.build());
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_197_UNIT_TO_UNIT_ANSWER_REQUEST_EXTENDED:
|
||||
if(mac instanceof UnitToUnitAnswerRequestExtended)
|
||||
@@ -930,7 +975,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icUnitAnswerRequestExtended)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_204_RADIO_UNIT_MONITOR_COMMAND_EXTENDED:
|
||||
if(mac instanceof RadioUnitMonitorCommandExtended)
|
||||
@@ -948,7 +992,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icRequest)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_216_STATUS_UPDATE_EXTENDED:
|
||||
if(mac instanceof StatusUpdateExtended)
|
||||
@@ -965,7 +1008,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icStatusUpdate)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_218_STATUS_QUERY_EXTENDED:
|
||||
MutableIdentifierCollection icStatusQueryExtended = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers());
|
||||
@@ -978,7 +1020,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.details("STATUS QUERY")
|
||||
.identifiers(icStatusQueryExtended)
|
||||
.build());
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_220_MESSAGE_UPDATE_EXTENDED:
|
||||
if(mac instanceof MessageUpdateExtended)
|
||||
@@ -995,7 +1036,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icStatusUpdate)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_223_CALL_ALERT_EXTENDED:
|
||||
if(mac instanceof CallAlertExtended)
|
||||
@@ -1010,7 +1050,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icCallAlertExtended)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_228_EXTENDED_FUNCTION_COMMAND_EXTENDED:
|
||||
if(mac instanceof ExtendedFunctionCommandExtended)
|
||||
@@ -1028,7 +1067,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icExtendedFunction)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
case PHASE1_234_GROUP_AFFILIATION_QUERY_EXTENDED:
|
||||
if(mac instanceof GroupAffiliationQueryExtended)
|
||||
@@ -1045,7 +1083,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.identifiers(icGroupAffiliationQueryExtended)
|
||||
.build());
|
||||
}
|
||||
continueState(State.ACTIVE);
|
||||
break;
|
||||
|
||||
case PHASE1_115_IDENTIFIER_UPDATE_TDMA:
|
||||
@@ -1071,8 +1108,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
case PHASE1_196_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_EXTENDED:
|
||||
case UNKNOWN:
|
||||
default:
|
||||
continueState(State.ACTIVE);
|
||||
//ignore
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1135,7 +1170,15 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
.build();
|
||||
|
||||
broadcast(mCurrentCallEvent);
|
||||
broadcast(new DecoderStateEvent(this, Event.START, State.CALL, getTimeslot()));
|
||||
|
||||
if(isEncrypted())
|
||||
{
|
||||
broadcast(new DecoderStateEvent(this, Event.START, State.ENCRYPTED, getTimeslot()));
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcast(new DecoderStateEvent(this, Event.START, State.CALL, getTimeslot()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1152,7 +1195,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
mCurrentCallEvent.setIdentifierCollection(getIdentifierCollection().copyOf());
|
||||
mCurrentCallEvent.end(timestamp);
|
||||
broadcast(mCurrentCallEvent);
|
||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL, getTimeslot()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1160,8 +1202,10 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
* Ends/closes the current call event.
|
||||
*
|
||||
* @param timestamp of the message that indicates the event has ended.
|
||||
* @param resetIdentifiers to reset the FROM/TO identifiers
|
||||
* @param pduType of the message that caused the close call event - to determine channel state after call
|
||||
*/
|
||||
private void closeCurrentCallEvent(long timestamp, boolean resetIdentifiers)
|
||||
private void closeCurrentCallEvent(long timestamp, boolean resetIdentifiers, MacPduType pduType)
|
||||
{
|
||||
if(mCurrentCallEvent != null)
|
||||
{
|
||||
@@ -1169,21 +1213,21 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
broadcast(mCurrentCallEvent);
|
||||
mCurrentCallEvent = null;
|
||||
|
||||
broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.ACTIVE, getTimeslot()));
|
||||
}
|
||||
else
|
||||
{
|
||||
continueState(State.ACTIVE);
|
||||
}
|
||||
broadcast(new DecoderStateEvent(this, Event.END, getStateFromPduType(pduType), getTimeslot()));
|
||||
|
||||
if(resetIdentifiers)
|
||||
{
|
||||
getIdentifierCollection().remove(IdentifierClass.USER);
|
||||
if(resetIdentifiers)
|
||||
{
|
||||
getIdentifierCollection().remove(IdentifierClass.USER);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Only clear the from identifier at this point ... the channel may still be allocated to the TO talkgroup
|
||||
getIdentifierCollection().remove(IdentifierClass.USER, Role.FROM);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if(pduType == MacPduType.MAC_2_END_PTT)
|
||||
{
|
||||
//Only clear the from identifier at this point ... the channel may still be allocated to the TO talkgroup
|
||||
getIdentifierCollection().remove(IdentifierClass.USER, Role.FROM);
|
||||
broadcast(new DecoderStateEvent(this, Event.END, getStateFromPduType(pduType), getTimeslot()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1215,14 +1259,17 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
@Override
|
||||
public void receiveDecoderStateEvent(DecoderStateEvent event)
|
||||
{
|
||||
switch(event.getEvent())
|
||||
if(event.getTimeslot() == getTimeslot())
|
||||
{
|
||||
case RESET:
|
||||
resetState();
|
||||
mNetworkConfigurationMonitor.reset();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case RESET:
|
||||
resetState();
|
||||
mNetworkConfigurationMonitor.reset();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -224,25 +224,30 @@ public class P25P2MessageFramer implements Listener<Dibit>
|
||||
public static void main(String[] args)
|
||||
{
|
||||
UserPreferences userPreferences = new UserPreferences();
|
||||
userPreferences.getJmbeLibraryPreference().setPathJmbeLibrary(Path.of("/home/denny/JMBE/jmbe-1.0.2.jar"));
|
||||
userPreferences.getJmbeLibraryPreference().setPathJmbeLibrary(Path.of("/home/denny/JMBE/jmbe-1.0.3.jar"));
|
||||
ApplicationLog applicationLog = new ApplicationLog(userPreferences);
|
||||
applicationLog.start();
|
||||
|
||||
// Path directory = Paths.get("/home/denny/SDRTrunk/recordings");
|
||||
Path directory = Paths.get("/home/denny/temp/Harris P25-2 Logs/bits");
|
||||
// Path directory = Paths.get("/media/denny/500G1EXT4/PBITRecordings");
|
||||
|
||||
// ScrambleParameters scrambleParameters = new ScrambleParameters(781824, 1186, 1189); //Nugent
|
||||
ScrambleParameters scrambleParameters = new ScrambleParameters(123654, 813, 10); //Hills
|
||||
// ScrambleParameters scrambleParameters = new ScrambleParameters(1, 972, 972));
|
||||
// ScrambleParameters scrambleParameters = new ScrambleParameters(781824, 686, 677)); //CNYICC - Rome
|
||||
// ScrambleParameters scrambleParameters = new ScrambleParameters(781824, 686, 677); //CNYICC - Rome
|
||||
|
||||
// Channel channel = new Channel("Phase 2 Test", Channel.ChannelType.STANDARD);
|
||||
Channel channel = new Channel("Phase 2 Test", Channel.ChannelType.TRAFFIC);
|
||||
|
||||
Channel channel = new Channel("Phase 2 Test");
|
||||
channel.setDecodeConfiguration(new DecodeConfigP25Phase2());
|
||||
AliasList aliasList = new AliasList("Test Alias List");
|
||||
Alias alias = new Alias("TG Range 1-65535");
|
||||
alias.addAliasID(new Record());
|
||||
// Alias alias = new Alias("TG Range 1-65535");
|
||||
// alias.addAliasID(new Record());
|
||||
// alias.addAliasID(new TalkgroupRange(Protocol.APCO25, 1, 65535));
|
||||
alias.addAliasID(new Talkgroup(Protocol.APCO25, 11185));
|
||||
aliasList.addAlias(alias);
|
||||
// alias.addAliasID(new Talkgroup(Protocol.APCO25, 11857));
|
||||
// alias.addAliasID(new Talkgroup(Protocol.APCO25, 12601));
|
||||
// aliasList.addAlias(alias);
|
||||
AudioRecordingManager recordingManager = new AudioRecordingManager(userPreferences);
|
||||
recordingManager.start();
|
||||
ProcessingChain processingChain = new ProcessingChain(channel, new AliasModel());
|
||||
@@ -254,20 +259,21 @@ public class P25P2MessageFramer implements Listener<Dibit>
|
||||
processingChain.addModule(new P25P2AudioModule(userPreferences, 1, aliasList));
|
||||
MessageProviderModule messageProviderModule = new MessageProviderModule();
|
||||
processingChain.addModule(messageProviderModule);
|
||||
processingChain.start();
|
||||
|
||||
try(OutputStream logOutput = Files.newOutputStream(directory.resolve("log.txt")))
|
||||
{
|
||||
try
|
||||
{
|
||||
DirectoryStream<Path> stream = Files.newDirectoryStream(directory, "*PHASE2_Hills*TRAFFIC.bits");
|
||||
// DirectoryStream<Path> stream = Files.newDirectoryStream(directory, "*042102*TRAFFIC.bits");
|
||||
// DirectoryStream<Path> stream = Files.newDirectoryStream(directory, "*042102*.bits");
|
||||
DirectoryStream<Path> stream = Files.newDirectoryStream(directory, "*214601*Hills*TRAFFIC.bits");
|
||||
|
||||
stream.forEach(new Consumer<Path>()
|
||||
{
|
||||
@Override
|
||||
public void accept(Path path)
|
||||
{
|
||||
mLog.debug("Processing:" + path.toString());
|
||||
mLog.debug("\n\nProcessing:" + path.toString() + "\n\n");
|
||||
try
|
||||
{
|
||||
logOutput.write(("Processing:" + path.toString() + "\n").getBytes());
|
||||
@@ -277,6 +283,8 @@ public class P25P2MessageFramer implements Listener<Dibit>
|
||||
mLog.error("Error", ioe);
|
||||
}
|
||||
|
||||
processingChain.start();
|
||||
|
||||
P25P2MessageFramer messageFramer = new P25P2MessageFramer(null, DecoderType.P25_PHASE2.getProtocol().getBitRate());
|
||||
messageFramer.setScrambleParameters(scrambleParameters);
|
||||
P25P2MessageProcessor messageProcessor = new P25P2MessageProcessor();
|
||||
@@ -313,6 +321,12 @@ public class P25P2MessageFramer implements Listener<Dibit>
|
||||
{
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
||||
mLog.debug("**STOPPING PROCESSING CHAIN**");
|
||||
|
||||
processingChain.stop();
|
||||
|
||||
mLog.debug("\n============================================================================================================================\n");
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -326,5 +340,7 @@ public class P25P2MessageFramer implements Listener<Dibit>
|
||||
{
|
||||
mLog.error("Error", ioe);
|
||||
}
|
||||
|
||||
recordingManager.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,22 @@ public enum DataUnitID
|
||||
return mValueWithParity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this DUID is a SACCH, either scrambled or unscrambled
|
||||
*/
|
||||
public boolean isSACCH()
|
||||
{
|
||||
return this == SCRAMBLED_SACCH || this == UNSCRAMBLED_SACCH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this DUID is a FACCH, either scrambled or unscrambled
|
||||
*/
|
||||
public boolean isFACCH()
|
||||
{
|
||||
return this == SCRAMBLED_FACCH || this == UNSCRAMBLED_FACCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user