mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-10 23:57:25 -05:00
Compare commits
22 Commits
v0.3.0-bet
...
v0.3.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5efd89632e | ||
|
|
1dc3863489 | ||
|
|
441286ba13 | ||
|
|
e4323df347 | ||
|
|
a872e0d664 | ||
|
|
fbc92cfe31 | ||
|
|
1a432197ac | ||
|
|
fbc6e508bd | ||
|
|
f9b6e67b00 | ||
|
|
a628800a71 | ||
|
|
25f71a76c4 | ||
|
|
5fe8ccd478 | ||
|
|
069f951a86 | ||
|
|
dab6df7836 | ||
|
|
89da46b63c | ||
|
|
5f2ce2a9f2 | ||
|
|
7a0b377971 | ||
|
|
5dbe0ecce3 | ||
|
|
6647c581a6 | ||
|
|
a2ab5bfa95 | ||
|
|
ed486440b8 | ||
|
|
13464e01fc |
@@ -7,7 +7,7 @@
|
||||
<property name="major" value="0"/>
|
||||
<property name="minor" value="3"/>
|
||||
<property name="patch" value="0"/>
|
||||
<property name="release" value="-beta8"/>
|
||||
<property name="release" value="-beta12"/>
|
||||
<property name="filename" value="sdrtrunk_${major}.${minor}.${patch}${release}"/>
|
||||
|
||||
<!-- Build properties -->
|
||||
|
||||
@@ -90,7 +90,8 @@ public class AudioChannelPanel extends JPanel
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout(new MigLayout("align center center, insets 0 0 0 0", "[][][align right]0[grow,fill]", ""));
|
||||
setLayout(new MigLayout("align center center, insets 0 0 0 0",
|
||||
"[][][align right]0[grow,fill]", ""));
|
||||
setBackground(mBackgroundColor);
|
||||
|
||||
mMutedLabel.setFont(mFont);
|
||||
@@ -109,7 +110,7 @@ public class AudioChannelPanel extends JPanel
|
||||
|
||||
mTo.setFont(mFont);
|
||||
mTo.setForeground(mValueColor);
|
||||
add(mTo);
|
||||
add(mTo,"wmin 10lp");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -159,30 +160,40 @@ public class AudioChannelPanel extends JPanel
|
||||
* does not occur on the Swing event thread -- wrap any calls to this
|
||||
* method with an event thread call.
|
||||
*/
|
||||
private void updateLabel(JLabel valueLabel, String value, JLabel aliasLabel, Alias alias)
|
||||
private void updateLabel(JLabel textLabel, String value, JLabel iconLabel, Alias alias)
|
||||
{
|
||||
if(value != null)
|
||||
{
|
||||
|
||||
if(alias != null)
|
||||
{
|
||||
valueLabel.setText(alias.getName());
|
||||
aliasLabel.setIcon(mIconManager.getIcon(alias.getIconName(), 18));
|
||||
iconLabel.setIcon(mIconManager.getIcon(alias.getIconName(), 18));
|
||||
|
||||
String aliasName = alias.getName();
|
||||
|
||||
//Truncate label if length exceeds 33 characters - hack!
|
||||
if(aliasName.length() > 33)
|
||||
{
|
||||
textLabel.setText(aliasName.substring(0,30) + "...");
|
||||
}
|
||||
else
|
||||
{
|
||||
textLabel.setText(aliasName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
valueLabel.setText(value);
|
||||
aliasLabel.setIcon(null);
|
||||
iconLabel.setIcon(null);
|
||||
textLabel.setText(value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
valueLabel.setText("-----");
|
||||
aliasLabel.setIcon(null);
|
||||
iconLabel.setIcon(null);
|
||||
textLabel.setText("-----");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes audio metadata to update this panel's display values
|
||||
*/
|
||||
|
||||
@@ -33,8 +33,7 @@ public class AudioChannelsPanel extends JPanel
|
||||
|
||||
public AudioChannelsPanel(IconManager iconManager, SettingsManager settingsManager, IAudioController controller)
|
||||
{
|
||||
// setLayout(new MigLayout("insets 0 0 0 0", "[][grow,fill][][grow,fill]", "[grow,fill]"));
|
||||
setLayout(new MigLayout("insets 0 0 0 0", "[][sg,grow,fill][][sg,grow,fill]", "[grow,fill]"));
|
||||
setLayout(new MigLayout("insets 0 0 0 0", "[][sg abc,grow,fill][][sg abc,grow,fill]", "[grow,fill]"));
|
||||
|
||||
setBackground(Color.BLACK);
|
||||
|
||||
@@ -44,7 +43,7 @@ public class AudioChannelsPanel extends JPanel
|
||||
|
||||
for(int x = 0; x < outputs.size(); x++)
|
||||
{
|
||||
add(new AudioChannelPanel(iconManager, settingsManager, outputs.get(x)), "growx");
|
||||
add(new AudioChannelPanel(iconManager, settingsManager, outputs.get(x)));
|
||||
|
||||
if(x < outputs.size() - 1)
|
||||
{
|
||||
|
||||
@@ -63,13 +63,11 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
|
||||
private Listener<CallEvent> mCallEventListener;
|
||||
|
||||
private ChannelModel mChannelModel;
|
||||
private ChannelProcessingManager mChannelProcessingManager;
|
||||
private DecodeConfiguration mDecodeConfiguration;
|
||||
private RecordConfiguration mRecordConfiguration;
|
||||
private String mSystem;
|
||||
private String mSite;
|
||||
private String mAliasListName;
|
||||
private CallEvent mPreviousDoNotMonitorCallEvent;
|
||||
|
||||
/**
|
||||
* Monitors call events and allocates traffic decoder channels in response
|
||||
@@ -77,7 +75,6 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
|
||||
* traffic channel allocations.
|
||||
*
|
||||
* @param channelModel containing channels currently in use
|
||||
* @param channelProcessingManager
|
||||
* @param decodeConfiguration - decoder configuration to use for each
|
||||
* traffic channel allocation.
|
||||
* @param recordConfiguration - recording options for each traffic channel
|
||||
@@ -88,7 +85,6 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
|
||||
* in the pool
|
||||
*/
|
||||
public TrafficChannelManager(ChannelModel channelModel,
|
||||
ChannelProcessingManager channelProcessingManager,
|
||||
DecodeConfiguration decodeConfiguration,
|
||||
RecordConfiguration recordConfiguration,
|
||||
String system,
|
||||
@@ -97,7 +93,6 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
|
||||
int trafficChannelPoolSize)
|
||||
{
|
||||
mChannelModel = channelModel;
|
||||
mChannelProcessingManager = channelProcessingManager;
|
||||
mDecodeConfiguration = decodeConfiguration;
|
||||
mRecordConfiguration = recordConfiguration;
|
||||
mSystem = system;
|
||||
@@ -120,7 +115,6 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
|
||||
|
||||
mCallEventListener = null;
|
||||
mDecodeConfiguration = null;
|
||||
mPreviousDoNotMonitorCallEvent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,21 +191,7 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
|
||||
|
||||
long frequency = callEvent.getFrequency();
|
||||
|
||||
/* Check the from/to aliases for do not monitor priority */
|
||||
if(isDoNotMonitor(callEvent))
|
||||
{
|
||||
callEvent.setCallEventType(CallEventType.CALL_DO_NOT_MONITOR);
|
||||
|
||||
if(isSameCallEvent(mPreviousDoNotMonitorCallEvent, callEvent))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPreviousDoNotMonitorCallEvent = callEvent;
|
||||
}
|
||||
}
|
||||
else if(frequency > 0)
|
||||
if(frequency > 0)
|
||||
{
|
||||
Channel channel = getChannel(callEvent.getChannel(), new TunerChannel(Type.TRAFFIC,
|
||||
frequency, mDecodeConfiguration.getDecoderType().getChannelBandwidth()));
|
||||
@@ -330,31 +310,6 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for aliases that contain a do not follow/process priority.
|
||||
*
|
||||
* @param event
|
||||
* @return - true if there is an alias that has a do not process alias id
|
||||
*/
|
||||
private boolean isDoNotMonitor(CallEvent event)
|
||||
{
|
||||
Alias to = event.getToIDAlias();
|
||||
|
||||
if(to != null && to.hasCallPriority() && to.getCallPriority() == Priority.DO_NOT_MONITOR)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Alias from = event.getFromIDAlias();
|
||||
|
||||
if(from != null && from.hasCallPriority() && from.getCallPriority() == Priority.DO_NOT_MONITOR)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<DecoderStateEvent> getDecoderStateListener()
|
||||
{
|
||||
|
||||
@@ -320,7 +320,13 @@ public class ProcessingChain implements IChannelEventListener
|
||||
|
||||
if(module instanceof IFrequencyChangeListener)
|
||||
{
|
||||
mFrequencyChangeEventBroadcaster.addListener(((IFrequencyChangeListener) module).getFrequencyChangeListener());
|
||||
Listener<FrequencyChangeEvent> frequencyChangeEventListener =
|
||||
((IFrequencyChangeListener)module).getFrequencyChangeListener();
|
||||
|
||||
if(frequencyChangeEventListener != null)
|
||||
{
|
||||
mFrequencyChangeEventBroadcaster.addListener(frequencyChangeEventListener);
|
||||
}
|
||||
}
|
||||
|
||||
if(module instanceof IMessageListener)
|
||||
|
||||
@@ -222,7 +222,7 @@ public class DecoderFactory
|
||||
|
||||
if(channelType == ChannelType.STANDARD)
|
||||
{
|
||||
modules.add(new TrafficChannelManager(channelModel, channelProcessingManager, decodeConfig,
|
||||
modules.add(new TrafficChannelManager(channelModel, decodeConfig,
|
||||
channel.getRecordConfiguration(), channel.getSystem(), channel.getSite(),
|
||||
(aliasList != null ? aliasList.getName() : null), mptConfig.getTrafficChannelPoolSize()));
|
||||
}
|
||||
@@ -263,7 +263,7 @@ public class DecoderFactory
|
||||
|
||||
if(channelType == ChannelType.STANDARD)
|
||||
{
|
||||
modules.add(new TrafficChannelManager(channelModel, channelProcessingManager, decodeConfig,
|
||||
modules.add(new TrafficChannelManager(channelModel, decodeConfig,
|
||||
channel.getRecordConfiguration(), channel.getSystem(), channel.getSite(),
|
||||
(aliasList != null ? aliasList.getName() : null), p25Config.getTrafficChannelPoolSize()));
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public class LJ1200DecoderState extends DecoderState
|
||||
super(aliasList);
|
||||
|
||||
mAddressAttribute = new AliasedStringAttributeMonitor(Attribute.SECONDARY_ADDRESS_TO,
|
||||
getAttributeChangeRequestListener(), getAliasList(), AliasIDType.LOJACK);
|
||||
getAttributeChangeRequestListener(), getAliasList(), AliasIDType.SITE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -315,6 +315,8 @@ public class P25DecoderState extends DecoderState
|
||||
*/
|
||||
public void registerCallEvent(P25CallEvent event)
|
||||
{
|
||||
String channel = event.getChannel();
|
||||
|
||||
if(mChannelCallMap.containsKey(event.getChannel()))
|
||||
{
|
||||
P25CallEvent previousEvent = mChannelCallMap.remove(event.getChannel());
|
||||
@@ -419,7 +421,7 @@ public class P25DecoderState extends DecoderState
|
||||
mCurrentCallEvent = new P25CallEvent.Builder(CallEventType.CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(mCurrentChannel)
|
||||
.details((hdu.isEncrypted() ? "ENCRYPTED " : ""))
|
||||
.details((hdu.isEncryptedAudio() ? "ENCRYPTED " : ""))
|
||||
.frequency(mCurrentChannelFrequency)
|
||||
.to(to)
|
||||
.build();
|
||||
@@ -1105,7 +1107,7 @@ public class P25DecoderState extends DecoderState
|
||||
broadcast(new P25CallEvent.Builder(CallEventType.CALL_DETECT)
|
||||
.aliasList(getAliasList())
|
||||
.channel(gvcu.getChannelA())
|
||||
.details((gvcu.isEncrypted() ? "ENCRYPTED" : ""))
|
||||
.details((gvcu.isEncryptedLinkControlWord() ? "ENCRYPTED" : ""))
|
||||
.frequency(gvcu.getDownlinkFrequencyA())
|
||||
.to(userA)
|
||||
.build());
|
||||
@@ -1120,7 +1122,7 @@ public class P25DecoderState extends DecoderState
|
||||
broadcast(new P25CallEvent.Builder(CallEventType.CALL_DETECT)
|
||||
.aliasList(getAliasList())
|
||||
.channel(gvcu.getChannelB())
|
||||
.details((gvcu.isEncrypted() ? "ENCRYPTED" : ""))
|
||||
.details((gvcu.isEncryptedLinkControlWord() ? "ENCRYPTED" : ""))
|
||||
.frequency(gvcu.getDownlinkFrequencyB())
|
||||
.to(userB)
|
||||
.build());
|
||||
@@ -1149,7 +1151,7 @@ public class P25DecoderState extends DecoderState
|
||||
broadcast(new P25CallEvent.Builder(CallEventType.CALL_DETECT)
|
||||
.aliasList(getAliasList())
|
||||
.channel(gvcue.getTransmitChannel())
|
||||
.details((gvcue.isEncrypted() ? "ENCRYPTED" : ""))
|
||||
.details((gvcue.isEncryptedLinkControlWord() ? "ENCRYPTED" : ""))
|
||||
.frequency(gvcue.getDownlinkFrequency())
|
||||
.to(group)
|
||||
.build());
|
||||
@@ -1185,7 +1187,7 @@ public class P25DecoderState extends DecoderState
|
||||
if(mCurrentCallEvent.getDetails() == null)
|
||||
{
|
||||
mCurrentCallEvent.setDetails(
|
||||
(gvcuser.isEncrypted() ? "ENCRYPTED " : "") +
|
||||
(gvcuser.isEncryptedLinkControlWord() ? "ENCRYPTED " : "") +
|
||||
(gvcuser.isEmergency() ? "EMERGENCY " : ""));
|
||||
|
||||
broadcast(mCurrentCallEvent);
|
||||
@@ -1397,7 +1399,7 @@ public class P25DecoderState extends DecoderState
|
||||
if(mCurrentCallEvent.getDetails() == null)
|
||||
{
|
||||
mCurrentCallEvent.setDetails(
|
||||
(tivcu.isEncrypted() ? "ENCRYPTED " : "") +
|
||||
(tivcu.isEncryptedLinkControlWord() ? "ENCRYPTED " : "") +
|
||||
(tivcu.isEmergency() ? "EMERGENCY " : ""));
|
||||
|
||||
broadcast(mCurrentCallEvent);
|
||||
@@ -1480,7 +1482,7 @@ public class P25DecoderState extends DecoderState
|
||||
if(mCurrentCallEvent.getDetails() == null)
|
||||
{
|
||||
mCurrentCallEvent.setDetails(
|
||||
(uuvcu.isEncrypted() ? "ENCRYPTED " : "") +
|
||||
(uuvcu.isEncryptedLinkControlWord() ? "ENCRYPTED " : "") +
|
||||
(uuvcu.isEmergency() ? "EMERGENCY " : ""));
|
||||
|
||||
broadcast(mCurrentCallEvent);
|
||||
@@ -1557,6 +1559,7 @@ public class P25DecoderState extends DecoderState
|
||||
break;
|
||||
case IDENTIFIER_UPDATE_NON_VUHF:
|
||||
case IDENTIFIER_UPDATE_VHF_UHF_BANDS:
|
||||
case IDENTIFIER_UPDATE_TDMA:
|
||||
IdentifierUpdate iu = (IdentifierUpdate)tsbk;
|
||||
|
||||
if(!mBands.containsKey(iu.getIdentifier()))
|
||||
@@ -2735,6 +2738,7 @@ public class P25DecoderState extends DecoderState
|
||||
else
|
||||
{
|
||||
StringBuilder details = new StringBuilder();
|
||||
details.append(pgvcg.isTDMAChannel() ? "TDMA " : "");
|
||||
details.append(pgvcg.isEmergency() ? "EMERGENCY " : "");
|
||||
details.append("PRI:").append(pgvcg.getPriority());
|
||||
details.append(pgvcg.isEncryptedChannel() ? " ENCRYPTED" : "");
|
||||
@@ -2742,7 +2746,7 @@ public class P25DecoderState extends DecoderState
|
||||
|
||||
P25CallEvent event = new P25CallEvent.Builder(CallEventType.PATCH_GROUP_CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(channel + (pgvcg.isTDMAChannel() ? " TDMA" : ""))
|
||||
.channel(channel)
|
||||
.details(details.toString())
|
||||
.frequency(pgvcg.getDownlinkFrequency())
|
||||
.from(from)
|
||||
@@ -2775,8 +2779,9 @@ public class P25DecoderState extends DecoderState
|
||||
{
|
||||
P25CallEvent event = new P25CallEvent.Builder(CallEventType.PATCH_GROUP_CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(channel + (gvcgu.isTDMAChannel1() ? " TDMA" : ""))
|
||||
.details((gvcgu.isEncrypted() ? "ENCRYPTED " : ""))
|
||||
.channel(channel)
|
||||
.details((gvcgu.isTDMAChannel1() ? "TDMA " : "") +
|
||||
(gvcgu.isEncrypted() ? "ENCRYPTED " : ""))
|
||||
.frequency(gvcgu.getDownlinkFrequency1())
|
||||
.to(to)
|
||||
.build();
|
||||
@@ -2801,8 +2806,9 @@ public class P25DecoderState extends DecoderState
|
||||
{
|
||||
P25CallEvent event = new P25CallEvent.Builder(CallEventType.PATCH_GROUP_CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(channel2 + (gvcgu.isTDMAChannel2() ? " TDMA" : ""))
|
||||
.details((gvcgu.isEncrypted() ? "ENCRYPTED " : ""))
|
||||
.channel(channel2)
|
||||
.details((gvcgu.isTDMAChannel2() ? "TDMA " : "") +
|
||||
(gvcgu.isEncrypted() ? "ENCRYPTED " : ""))
|
||||
.frequency(gvcgu.getDownlinkFrequency2())
|
||||
.to(to2)
|
||||
.build();
|
||||
@@ -2866,6 +2872,7 @@ public class P25DecoderState extends DecoderState
|
||||
else
|
||||
{
|
||||
StringBuilder details = new StringBuilder();
|
||||
details.append(gdcg.isTDMAChannel() ? "TDMA " : "");
|
||||
details.append(gdcg.isEmergency() ? "EMERGENCY " : "");
|
||||
details.append("PRI:").append(gdcg.getPriority()).append(" ");
|
||||
details.append(gdcg.isEncryptedChannel() ? "ENCRYPTED " : "");
|
||||
@@ -2873,7 +2880,7 @@ public class P25DecoderState extends DecoderState
|
||||
|
||||
P25CallEvent event = new P25CallEvent.Builder(CallEventType.DATA_CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(channel + (gdcg.isTDMAChannel() ? " TDMA" : ""))
|
||||
.channel(channel)
|
||||
.details(details.toString())
|
||||
.frequency(gdcg.getDownlinkFrequency())
|
||||
.from(from)
|
||||
@@ -2904,6 +2911,7 @@ public class P25DecoderState extends DecoderState
|
||||
else
|
||||
{
|
||||
StringBuilder details = new StringBuilder();
|
||||
details.append(gvcg.isTDMAChannel() ? "TDMA " : "");
|
||||
details.append(gvcg.isEmergency() ? "EMERGENCY " : "");
|
||||
details.append("PRI:").append(gvcg.getPriority()).append(" ");
|
||||
details.append(gvcg.isEncryptedChannel() ? "ENCRYPTED " : "");
|
||||
@@ -2911,7 +2919,7 @@ public class P25DecoderState extends DecoderState
|
||||
|
||||
P25CallEvent event = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(channel + (gvcg.isTDMAChannel() ? " TDMA" : ""))
|
||||
.channel(channel)
|
||||
.details(details.toString())
|
||||
.frequency(gvcg.getDownlinkFrequency())
|
||||
.from(from)
|
||||
@@ -2928,8 +2936,7 @@ public class P25DecoderState extends DecoderState
|
||||
}
|
||||
break;
|
||||
case GROUP_VOICE_CHANNEL_GRANT_UPDATE:
|
||||
GroupVoiceChannelGrantUpdate gvcgu =
|
||||
(GroupVoiceChannelGrantUpdate)message;
|
||||
GroupVoiceChannelGrantUpdate gvcgu = (GroupVoiceChannelGrantUpdate)message;
|
||||
|
||||
channel = gvcgu.getChannel1();
|
||||
from = null;
|
||||
@@ -2942,6 +2949,7 @@ public class P25DecoderState extends DecoderState
|
||||
else
|
||||
{
|
||||
StringBuilder details = new StringBuilder();
|
||||
details.append(gvcgu.isTDMAChannel() ? "TDMA " : "");
|
||||
details.append(gvcgu.isEmergency() ? "EMERGENCY " : "");
|
||||
details.append("PRI:").append(gvcgu.getPriority()).append(" ");
|
||||
details.append(gvcgu.isEncryptedChannel() ? "ENCRYPTED " : "");
|
||||
@@ -2949,7 +2957,7 @@ public class P25DecoderState extends DecoderState
|
||||
|
||||
P25CallEvent event = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(gvcgu.getChannel1() + (gvcgu.isTDMAChannel1() ? " TDMA" : ""))
|
||||
.channel(gvcgu.getChannel1())
|
||||
.details(details.toString())
|
||||
.frequency(gvcgu.getDownlinkFrequency1())
|
||||
.from(from)
|
||||
@@ -2977,6 +2985,7 @@ public class P25DecoderState extends DecoderState
|
||||
else
|
||||
{
|
||||
StringBuilder details = new StringBuilder();
|
||||
details.append(gvcgu.isTDMAChannel() ? "TDMA " : "");
|
||||
details.append(gvcgu.isEmergency() ? "EMERGENCY " : "");
|
||||
details.append("PRI:").append(gvcgu.getPriority()).append(" ");
|
||||
details.append(gvcgu.isEncryptedChannel() ? "ENCRYPTED " : "");
|
||||
@@ -2984,7 +2993,7 @@ public class P25DecoderState extends DecoderState
|
||||
|
||||
P25CallEvent event2 = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(gvcgu.getChannel2() + (gvcgu.isTDMAChannel2() ? " TDMA" : ""))
|
||||
.channel(gvcgu.getChannel2())
|
||||
.details(details.toString())
|
||||
.frequency(gvcgu.getDownlinkFrequency2())
|
||||
.to(gvcgu.getGroupAddress2())
|
||||
@@ -3016,6 +3025,7 @@ public class P25DecoderState extends DecoderState
|
||||
else
|
||||
{
|
||||
StringBuilder details = new StringBuilder();
|
||||
details.append(gvcgue.isTDMAChannel() ? "TDMA " : "");
|
||||
details.append(gvcgue.isEmergency() ? "EMERGENCY " : "");
|
||||
details.append("PRI:").append(gvcgue.getPriority()).append(" ");
|
||||
details.append(gvcgue.isEncryptedChannel() ? "ENCRYPTED " : "");
|
||||
@@ -3023,7 +3033,7 @@ public class P25DecoderState extends DecoderState
|
||||
|
||||
P25CallEvent event = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(channel + (gvcgue.isTDMAChannel() ? " TDMA" : ""))
|
||||
.channel(channel)
|
||||
.details(details.toString())
|
||||
.frequency(gvcgue.getDownlinkFrequency())
|
||||
.from(from)
|
||||
@@ -3053,6 +3063,7 @@ public class P25DecoderState extends DecoderState
|
||||
else
|
||||
{
|
||||
StringBuilder details = new StringBuilder();
|
||||
details.append(idcg.isTDMAChannel() ? "TDMA " : "");
|
||||
details.append(idcg.isEmergency() ? "EMERGENCY " : "");
|
||||
details.append("PRI:").append(idcg.getPriority()).append(" ");
|
||||
details.append(idcg.isEncryptedChannel() ? "ENCRYPTED " : "");
|
||||
@@ -3060,7 +3071,7 @@ public class P25DecoderState extends DecoderState
|
||||
|
||||
P25CallEvent event = new P25CallEvent.Builder(CallEventType.DATA_CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(channel + (idcg.isTDMAChannel() ? " TDMA" : ""))
|
||||
.channel(channel)
|
||||
.details(details.toString())
|
||||
.frequency(idcg.getDownlinkFrequency())
|
||||
.from(from)
|
||||
@@ -3090,13 +3101,14 @@ public class P25DecoderState extends DecoderState
|
||||
else
|
||||
{
|
||||
StringBuilder details = new StringBuilder();
|
||||
details.append(sdcg.isTDMAChannel() ? "TDMA " : "");
|
||||
details.append(sdcg.isEmergency() ? "EMERGENCY " : "");
|
||||
details.append(sdcg.isEncryptedChannel() ? "ENCRYPTED " : "");
|
||||
details.append(sdcg.getSessionMode().name());
|
||||
|
||||
P25CallEvent event = new P25CallEvent.Builder(CallEventType.DATA_CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(channel + (sdcg.isTDMAChannel() ? " TDMA" : ""))
|
||||
.channel(channel)
|
||||
.details(details.toString())
|
||||
.frequency(sdcg.getDownlinkFrequency())
|
||||
.from(from)
|
||||
@@ -3128,6 +3140,7 @@ public class P25DecoderState extends DecoderState
|
||||
else
|
||||
{
|
||||
StringBuilder details = new StringBuilder();
|
||||
details.append(tivcg.isTDMAChannel() ? "TDMA " : "");
|
||||
details.append(tivcg.isEmergency() ? "EMERGENCY " : "");
|
||||
details.append("PRI:").append(tivcg.getPriority()).append(" ");
|
||||
details.append(tivcg.isEncryptedChannel() ? "ENCRYPTED " : "");
|
||||
@@ -3137,7 +3150,7 @@ public class P25DecoderState extends DecoderState
|
||||
P25CallEvent event = new P25CallEvent.Builder(
|
||||
CallEventType.TELEPHONE_INTERCONNECT)
|
||||
.aliasList(getAliasList())
|
||||
.channel(channel + (tivcg.isTDMAChannel() ? " TDMA" : ""))
|
||||
.channel(channel)
|
||||
.details(details.toString())
|
||||
.frequency(tivcg.getDownlinkFrequency())
|
||||
.from(from)
|
||||
@@ -3170,6 +3183,7 @@ public class P25DecoderState extends DecoderState
|
||||
else
|
||||
{
|
||||
StringBuilder details = new StringBuilder();
|
||||
details.append(tivcgu.isTDMAChannel() ? "TDMA " : "");
|
||||
details.append(tivcgu.isEmergency() ? "EMERGENCY " : "");
|
||||
details.append("PRI:").append(tivcgu.getPriority()).append(" ");
|
||||
details.append(tivcgu.isEncryptedChannel() ? "ENCRYPTED " : "");
|
||||
@@ -3179,7 +3193,7 @@ public class P25DecoderState extends DecoderState
|
||||
P25CallEvent event = new P25CallEvent.Builder(
|
||||
CallEventType.TELEPHONE_INTERCONNECT)
|
||||
.aliasList(getAliasList())
|
||||
.channel(channel + (tivcgu.isTDMAChannel() ? " TDMA" : ""))
|
||||
.channel(channel)
|
||||
.details(details.toString())
|
||||
.frequency(tivcgu.getDownlinkFrequency())
|
||||
.from(from)
|
||||
@@ -3209,6 +3223,7 @@ public class P25DecoderState extends DecoderState
|
||||
else
|
||||
{
|
||||
StringBuilder details = new StringBuilder();
|
||||
details.append(uuvcg.isTDMAChannel() ? "TDMA " : "");
|
||||
details.append(uuvcg.isEmergency() ? "EMERGENCY " : "");
|
||||
details.append("PRI:").append(uuvcg.getPriority()).append(" ");
|
||||
details.append(uuvcg.isEncryptedChannel() ? " ENCRYPTED " : "");
|
||||
@@ -3217,7 +3232,7 @@ public class P25DecoderState extends DecoderState
|
||||
P25CallEvent event = new P25CallEvent.Builder(
|
||||
CallEventType.UNIT_TO_UNIT_CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(channel + (uuvcg.isTDMAChannel() ? " TDMA" : ""))
|
||||
.channel(channel)
|
||||
.details(details.toString())
|
||||
.frequency(uuvcg.getDownlinkFrequency())
|
||||
.from(from)
|
||||
@@ -3247,6 +3262,7 @@ public class P25DecoderState extends DecoderState
|
||||
else
|
||||
{
|
||||
StringBuilder details = new StringBuilder();
|
||||
details.append(uuvcgu.isTDMAChannel() ? "TDMA " : "");
|
||||
details.append(uuvcgu.isEmergency() ? "EMERGENCY " : "");
|
||||
details.append("PRI:").append(uuvcgu.getPriority()).append(" ");
|
||||
details.append(uuvcgu.isEncryptedChannel() ? "ENCRYPTED " : "");
|
||||
@@ -3255,7 +3271,7 @@ public class P25DecoderState extends DecoderState
|
||||
P25CallEvent event = new P25CallEvent.Builder(
|
||||
CallEventType.UNIT_TO_UNIT_CALL)
|
||||
.aliasList(getAliasList())
|
||||
.channel(channel + (uuvcgu.isTDMAChannel() ? " TDMA" : ""))
|
||||
.channel(channel)
|
||||
.details(details.toString())
|
||||
.frequency(uuvcgu.getDownlinkFrequency())
|
||||
.from(from)
|
||||
|
||||
@@ -12,6 +12,9 @@ import jmbe.iface.AudioConverter;
|
||||
import message.IMessageListener;
|
||||
import message.Message;
|
||||
import module.Module;
|
||||
import module.decode.p25.message.hdu.HDUMessage;
|
||||
import module.decode.p25.message.ldu.LDU1Message;
|
||||
import module.decode.p25.message.ldu.LDU2Message;
|
||||
import module.decode.p25.message.ldu.LDUMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -25,14 +28,18 @@ public class P25AudioModule extends Module implements Listener<Message>, IAudioP
|
||||
private final static Logger mLog = LoggerFactory.getLogger(P25AudioModule.class);
|
||||
|
||||
private static final String IMBE_CODEC = "IMBE";
|
||||
|
||||
private static boolean mLibraryLoadStatusLogged = false;
|
||||
|
||||
private boolean mCanConvertAudio = false;
|
||||
private boolean mEncryptedCall = false;
|
||||
private boolean mEncryptedCallStateEstablished = false;
|
||||
|
||||
private AudioConverter mAudioConverter;
|
||||
private Listener<AudioPacket> mAudioPacketListener;
|
||||
private SquelchStateListener mSquelchStateListener = new SquelchStateListener();
|
||||
private NonClippingGain mGain = new NonClippingGain(5.0f, 0.95f);
|
||||
private Metadata mMetadata;
|
||||
private LDU1Message mCachedLDU1Message = null;
|
||||
|
||||
public P25AudioModule(Metadata metadata)
|
||||
{
|
||||
@@ -76,32 +83,73 @@ public class P25AudioModule extends Module implements Listener<Message>, IAudioP
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary processing method for p25 imbe audio frame messages. Each LDU
|
||||
* audio message contains 9 imbe voice frames. Each frame is converted to
|
||||
* audio when the JMBE library is loaded, processed by auto-gain, and
|
||||
* broadcast to the audio packet listener.
|
||||
* Processes call header (HDU) and voice frame (LDU1/LDU2) messages to decode audio and to determine the
|
||||
* encrypted audio status of a call event. Only the HDU and LDU2 messages convey encrypted call status. If an
|
||||
* LDU1 message is received without a preceding HDU message, then the LDU1 message is cached until the first
|
||||
* LDU2 message is received and the encryption state can be determined. Both the LDU1 and the LDU2 message are
|
||||
* then processed for audio if the call is unencrypted.
|
||||
*/
|
||||
public void receive(Message message)
|
||||
{
|
||||
if (mCanConvertAudio && mAudioPacketListener != null)
|
||||
if(mCanConvertAudio && mAudioPacketListener != null)
|
||||
{
|
||||
if (message instanceof LDUMessage)
|
||||
if(mEncryptedCallStateEstablished)
|
||||
{
|
||||
LDUMessage ldu = (LDUMessage) message;
|
||||
|
||||
/* Only process unencrypted audio frames */
|
||||
if (!(ldu.isValid() && ldu.isEncrypted()))
|
||||
if(message instanceof LDUMessage)
|
||||
{
|
||||
for (byte[] frame : ldu.getIMBEFrames())
|
||||
{
|
||||
float[] audio = mAudioConverter.decode(frame);
|
||||
|
||||
audio = mGain.apply(audio);
|
||||
|
||||
mAudioPacketListener.receive(new AudioPacket(audio, mMetadata.copyOf()));
|
||||
}
|
||||
processAudio((LDUMessage)message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(message instanceof HDUMessage)
|
||||
{
|
||||
mEncryptedCallStateEstablished = true;
|
||||
mEncryptedCall = ((HDUMessage)message).isEncryptedAudio();
|
||||
}
|
||||
else if(message instanceof LDU1Message)
|
||||
{
|
||||
//When we receive an LDU1 message with first receiving the HDU message, cache the LDU1 Message
|
||||
//until we can determine the encrypted call state from the next LDU2 message
|
||||
mCachedLDU1Message = (LDU1Message)message;
|
||||
}
|
||||
else if(message instanceof LDU2Message)
|
||||
{
|
||||
mEncryptedCallStateEstablished = true;
|
||||
LDU2Message ldu2 = (LDU2Message)message;
|
||||
mEncryptedCall = ldu2.isEncryptedAudio();
|
||||
|
||||
if(mCachedLDU1Message != null)
|
||||
{
|
||||
processAudio(mCachedLDU1Message);
|
||||
mCachedLDU1Message = null;
|
||||
}
|
||||
|
||||
processAudio(ldu2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an audio packet by decoding the IMBE audio frames and rebroadcasting them as PCM audio packets.
|
||||
*/
|
||||
private void processAudio(LDUMessage ldu)
|
||||
{
|
||||
if(!mEncryptedCall)
|
||||
{
|
||||
for(byte[] frame : ldu.getIMBEFrames())
|
||||
{
|
||||
float[] audio = mAudioConverter.decode(frame);
|
||||
|
||||
audio = mGain.apply(audio);
|
||||
|
||||
mAudioPacketListener.receive(new AudioPacket(audio, mMetadata.copyOf()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Encrypted audio processing not implemented
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,18 +167,18 @@ public class P25AudioModule extends Module implements Listener<Message>, IAudioP
|
||||
@SuppressWarnings("rawtypes")
|
||||
Class temp = Class.forName("jmbe.JMBEAudioLibrary");
|
||||
|
||||
library = (AudioConversionLibrary) temp.newInstance();
|
||||
library = (AudioConversionLibrary)temp.newInstance();
|
||||
|
||||
if ((library.getMajorVersion() == 0 && library.getMinorVersion() >= 3 &&
|
||||
library.getBuildVersion() >= 3) || library.getMajorVersion() >= 1)
|
||||
if((library.getMajorVersion() == 0 && library.getMinorVersion() >= 3 &&
|
||||
library.getBuildVersion() >= 3) || library.getMajorVersion() >= 1)
|
||||
{
|
||||
mAudioConverter = library.getAudioConverter(IMBE_CODEC, AudioFormats.PCM_SIGNED_8KHZ_16BITS_MONO);
|
||||
|
||||
if (mAudioConverter != null)
|
||||
if(mAudioConverter != null)
|
||||
{
|
||||
mCanConvertAudio = true;
|
||||
|
||||
if (!mLibraryLoadStatusLogged)
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("JMBE audio conversion library [");
|
||||
@@ -144,7 +192,7 @@ public class P25AudioModule extends Module implements Listener<Message>, IAudioP
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mLibraryLoadStatusLogged)
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.info("JMBE audio conversion library NOT FOUND");
|
||||
mLibraryLoadStatusLogged = true;
|
||||
@@ -156,28 +204,28 @@ public class P25AudioModule extends Module implements Listener<Message>, IAudioP
|
||||
mLog.warn("JMBE library version 0.3.3 or higher is required - found: " + library.getVersion());
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException e1)
|
||||
catch(ClassNotFoundException e1)
|
||||
{
|
||||
if (!mLibraryLoadStatusLogged)
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.error("Couldn't find/load JMBE audio conversion library");
|
||||
mLibraryLoadStatusLogged = true;
|
||||
}
|
||||
}
|
||||
catch (InstantiationException e1)
|
||||
catch(InstantiationException e1)
|
||||
{
|
||||
if (!mLibraryLoadStatusLogged)
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.error("Couldn't instantiate JMBE audio conversion library class");
|
||||
mLibraryLoadStatusLogged = true;
|
||||
}
|
||||
}
|
||||
catch (IllegalAccessException e1)
|
||||
catch(IllegalAccessException e1)
|
||||
{
|
||||
if (!mLibraryLoadStatusLogged)
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.error("Couldn't load JMBE audio conversion library due to "
|
||||
+ "security restrictions");
|
||||
+ "security restrictions");
|
||||
mLibraryLoadStatusLogged = true;
|
||||
}
|
||||
}
|
||||
@@ -196,19 +244,25 @@ public class P25AudioModule extends Module implements Listener<Message>, IAudioP
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for squelch state listener. Internally, the P25 audio module
|
||||
* doesn't have a squelch state. If there are IMBE audio frames, we have
|
||||
* audio. We use this listener to signal to the recorder manager that the
|
||||
* channel state is resetting and it should end the recording.
|
||||
* Wrapper for squelch state to process end of call actions. At call end the encrypted call state established
|
||||
* flag is reset so that the encrypted audio state for the next call can be properly detected and we send an
|
||||
* END audio packet so that downstream processors like the audio recorder can properly close out a call sequence.
|
||||
*/
|
||||
public class SquelchStateListener implements Listener<SquelchState>
|
||||
{
|
||||
@Override
|
||||
public void receive(SquelchState state)
|
||||
{
|
||||
if (state == SquelchState.SQUELCH && mAudioPacketListener != null)
|
||||
if(state == SquelchState.SQUELCH)
|
||||
{
|
||||
mAudioPacketListener.receive(new AudioPacket(AudioPacket.Type.END, mMetadata.copyOf()));
|
||||
if(mAudioPacketListener != null)
|
||||
{
|
||||
mAudioPacketListener.receive(new AudioPacket(AudioPacket.Type.END, mMetadata.copyOf()));
|
||||
}
|
||||
|
||||
mEncryptedCallStateEstablished = false;
|
||||
mEncryptedCall = false;
|
||||
mCachedLDU1Message = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ public class HDUMessage extends P25Message
|
||||
return Encryption.fromValue( mMessage.getInt( ALGORITHM_ID ) );
|
||||
}
|
||||
|
||||
public boolean isEncrypted()
|
||||
public boolean isEncryptedAudio()
|
||||
{
|
||||
return getEncryption() != Encryption.UNENCRYPTED;
|
||||
}
|
||||
|
||||
@@ -1,244 +1,246 @@
|
||||
package module.decode.p25.message.ldu;
|
||||
|
||||
import module.decode.p25.reference.DataUnitID;
|
||||
import module.decode.p25.reference.LinkControlOpcode;
|
||||
import module.decode.p25.reference.Vendor;
|
||||
import module.decode.p25.reference.VendorLinkControlOpcode;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import alias.AliasList;
|
||||
import bits.BinaryMessage;
|
||||
import edac.CRC;
|
||||
import edac.Hamming10;
|
||||
import edac.ReedSolomon_63_47_17;
|
||||
import module.decode.p25.reference.DataUnitID;
|
||||
import module.decode.p25.reference.LinkControlOpcode;
|
||||
import module.decode.p25.reference.Vendor;
|
||||
import module.decode.p25.reference.VendorLinkControlOpcode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class LDU1Message extends LDUMessage
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( LDU1Message.class );
|
||||
|
||||
public static final int ENCRYPTION_FLAG = 352;
|
||||
public static final int IMPLICIT_VENDOR_FLAG = 353;
|
||||
public static final int[] OPCODE = { 354,355,356,357,362,363 };
|
||||
public static final int[] VENDOR = { 364,365,366,367,372,373,374,375 };
|
||||
|
||||
public static final int[] GOLAY_WORD_STARTS = {
|
||||
352,362,372,382,536,546,556,566,720,730,740,750,904,914,924,934,1088,
|
||||
1098,1108,1118,1272,1282,1292,1302 };
|
||||
private final static Logger mLog = LoggerFactory.getLogger(LDU1Message.class);
|
||||
|
||||
public static final int[] CW_HEX_0 = { 352,353,354,355,356,357 };
|
||||
public static final int[] CW_HEX_1 = { 362,363,364,365,366,367 };
|
||||
public static final int[] CW_HEX_2 = { 372,373,374,375,376,377 };
|
||||
public static final int[] CW_HEX_3 = { 382,383,384,385,386,387 };
|
||||
public static final int[] CW_HEX_4 = { 536,537,538,539,540,541 };
|
||||
public static final int[] CW_HEX_5 = { 546,547,548,549,550,551 };
|
||||
public static final int[] CW_HEX_6 = { 556,557,558,559,560,561 };
|
||||
public static final int[] CW_HEX_7 = { 566,567,568,569,570,571 };
|
||||
public static final int[] CW_HEX_8 = { 720,721,722,723,724,725 };
|
||||
public static final int[] CW_HEX_9 = { 730,731,732,733,734,735 };
|
||||
public static final int[] CW_HEX_10 = { 740,741,742,743,744,745 };
|
||||
public static final int[] CW_HEX_11 = { 750,751,752,753,754,755 };
|
||||
public static final int[] RS_HEX_0 = { 904,905,906,907,908,909 };
|
||||
public static final int[] RS_HEX_1 = { 914,915,916,917,918,919 };
|
||||
public static final int[] RS_HEX_2 = { 924,925,926,927,928,929 };
|
||||
public static final int[] RS_HEX_3 = { 934,935,936,937,938,939 };
|
||||
public static final int[] RS_HEX_4 = { 1088,1089,1090,1091,1092,1093 };
|
||||
public static final int[] RS_HEX_5 = { 1098,1099,1100,1101,1102,1103 };
|
||||
public static final int[] RS_HEX_6 = { 1108,1109,1110,1111,1112,1113 };
|
||||
public static final int[] RS_HEX_7 = { 1118,1119,1120,1121,1122,1123 };
|
||||
public static final int[] RS_HEX_8 = { 1272,1273,1274,1275,1276,1277 };
|
||||
public static final int[] RS_HEX_9 = { 1282,1283,1284,1285,1286,1287 };
|
||||
public static final int[] RS_HEX_10 = { 1292,1293,1294,1295,1296,1297 };
|
||||
public static final int[] RS_HEX_11 = { 1302,1303,1304,1305,1306,1307 };
|
||||
public static final int ENCRYPTED_LINK_CONTROL_WORD_FLAG = 352;
|
||||
public static final int IMPLICIT_VENDOR_FLAG = 353;
|
||||
public static final int[] OPCODE = {354, 355, 356, 357, 362, 363};
|
||||
public static final int[] VENDOR = {364, 365, 366, 367, 372, 373, 374, 375};
|
||||
|
||||
/* Reed-Solomon(24,12,13) code protects the link control word. Maximum
|
||||
* correctable errors are: Hamming Distance(13) / 2 = 6 */
|
||||
public static final ReedSolomon_63_47_17 mReedSolomonDecoder =
|
||||
new ReedSolomon_63_47_17( 6 );
|
||||
public static final int[] GOLAY_WORD_STARTS = {
|
||||
352, 362, 372, 382, 536, 546, 556, 566, 720, 730, 740, 750, 904, 914, 924, 934, 1088,
|
||||
1098, 1108, 1118, 1272, 1282, 1292, 1302};
|
||||
|
||||
public LDU1Message( BinaryMessage message, DataUnitID duid,
|
||||
AliasList aliasList )
|
||||
public static final int[] CW_HEX_0 = {352, 353, 354, 355, 356, 357};
|
||||
public static final int[] CW_HEX_1 = {362, 363, 364, 365, 366, 367};
|
||||
public static final int[] CW_HEX_2 = {372, 373, 374, 375, 376, 377};
|
||||
public static final int[] CW_HEX_3 = {382, 383, 384, 385, 386, 387};
|
||||
public static final int[] CW_HEX_4 = {536, 537, 538, 539, 540, 541};
|
||||
public static final int[] CW_HEX_5 = {546, 547, 548, 549, 550, 551};
|
||||
public static final int[] CW_HEX_6 = {556, 557, 558, 559, 560, 561};
|
||||
public static final int[] CW_HEX_7 = {566, 567, 568, 569, 570, 571};
|
||||
public static final int[] CW_HEX_8 = {720, 721, 722, 723, 724, 725};
|
||||
public static final int[] CW_HEX_9 = {730, 731, 732, 733, 734, 735};
|
||||
public static final int[] CW_HEX_10 = {740, 741, 742, 743, 744, 745};
|
||||
public static final int[] CW_HEX_11 = {750, 751, 752, 753, 754, 755};
|
||||
public static final int[] RS_HEX_0 = {904, 905, 906, 907, 908, 909};
|
||||
public static final int[] RS_HEX_1 = {914, 915, 916, 917, 918, 919};
|
||||
public static final int[] RS_HEX_2 = {924, 925, 926, 927, 928, 929};
|
||||
public static final int[] RS_HEX_3 = {934, 935, 936, 937, 938, 939};
|
||||
public static final int[] RS_HEX_4 = {1088, 1089, 1090, 1091, 1092, 1093};
|
||||
public static final int[] RS_HEX_5 = {1098, 1099, 1100, 1101, 1102, 1103};
|
||||
public static final int[] RS_HEX_6 = {1108, 1109, 1110, 1111, 1112, 1113};
|
||||
public static final int[] RS_HEX_7 = {1118, 1119, 1120, 1121, 1122, 1123};
|
||||
public static final int[] RS_HEX_8 = {1272, 1273, 1274, 1275, 1276, 1277};
|
||||
public static final int[] RS_HEX_9 = {1282, 1283, 1284, 1285, 1286, 1287};
|
||||
public static final int[] RS_HEX_10 = {1292, 1293, 1294, 1295, 1296, 1297};
|
||||
public static final int[] RS_HEX_11 = {1302, 1303, 1304, 1305, 1306, 1307};
|
||||
|
||||
/* Reed-Solomon(24,12,13) code protects the link control word. Maximum
|
||||
* correctable errors are: Hamming Distance(13) / 2 = 6 */
|
||||
public static final ReedSolomon_63_47_17 mReedSolomonDecoder =
|
||||
new ReedSolomon_63_47_17(6);
|
||||
|
||||
public LDU1Message(BinaryMessage message, DataUnitID duid,
|
||||
AliasList aliasList)
|
||||
{
|
||||
super( message, duid, aliasList );
|
||||
super(message, duid, aliasList);
|
||||
|
||||
|
||||
/* NID CRC is checked in the message framer, thus a constructed message
|
||||
* means it passed the CRC */
|
||||
mCRC = new CRC[ 3 ];
|
||||
mCRC[ 0 ] = CRC.PASSED;
|
||||
|
||||
checkCRC();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass constructor from an existing LDU1Message
|
||||
*/
|
||||
protected LDU1Message( LDU1Message message )
|
||||
{
|
||||
super( message.getSourceMessage(), DataUnitID.LDU1, message.getAliasList() );
|
||||
|
||||
mCRC = message.mCRC;
|
||||
}
|
||||
* means it passed the CRC */
|
||||
mCRC = new CRC[3];
|
||||
mCRC[0] = CRC.PASSED;
|
||||
|
||||
@Override
|
||||
public boolean isEncrypted()
|
||||
{
|
||||
return mMessage.get( ENCRYPTION_FLAG );
|
||||
}
|
||||
|
||||
private void checkCRC()
|
||||
{
|
||||
mCRC[ 1 ] = CRC.PASSED;
|
||||
checkCRC();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass constructor from an existing LDU1Message
|
||||
*/
|
||||
protected LDU1Message(LDU1Message message)
|
||||
{
|
||||
super(message.getSourceMessage(), DataUnitID.LDU1, message.getAliasList());
|
||||
|
||||
mCRC = message.mCRC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the contents of the Link Control Word are encrypted.
|
||||
*
|
||||
* @return true if the contents of the LCW are encrypted.
|
||||
*/
|
||||
public boolean isEncryptedLinkControlWord()
|
||||
{
|
||||
return mMessage.get(ENCRYPTED_LINK_CONTROL_WORD_FLAG);
|
||||
}
|
||||
|
||||
private void checkCRC()
|
||||
{
|
||||
mCRC[1] = CRC.PASSED;
|
||||
|
||||
/* Hamming( 10,6,3 ) error detection and correction */
|
||||
for( int index: GOLAY_WORD_STARTS )
|
||||
{
|
||||
int errors = Hamming10.checkAndCorrect( mMessage, index );
|
||||
|
||||
if( errors > 1 )
|
||||
{
|
||||
mCRC[ 1 ] = CRC.FAILED_CRC;
|
||||
}
|
||||
}
|
||||
for(int index : GOLAY_WORD_STARTS)
|
||||
{
|
||||
int errors = Hamming10.checkAndCorrect(mMessage, index);
|
||||
|
||||
if(errors > 1)
|
||||
{
|
||||
mCRC[1] = CRC.FAILED_CRC;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reed-Solomon( 24,16,9 ) error detection and correction
|
||||
* Check the Reed-Solomon parity bits. The RS decoder expects the code
|
||||
* words and reed solomon parity hex codewords in reverse order.
|
||||
*
|
||||
* Since this is a truncated RS(63) codes, we pad the code with zeros */
|
||||
int[] input = new int [63];
|
||||
int[] output = new int [63];
|
||||
|
||||
input[ 0 ] = mMessage.getInt( RS_HEX_11 );
|
||||
input[ 1 ] = mMessage.getInt( RS_HEX_10 );
|
||||
input[ 2 ] = mMessage.getInt( RS_HEX_9 );
|
||||
input[ 3 ] = mMessage.getInt( RS_HEX_8 );
|
||||
input[ 4 ] = mMessage.getInt( RS_HEX_7 );
|
||||
input[ 5 ] = mMessage.getInt( RS_HEX_6 );
|
||||
input[ 6 ] = mMessage.getInt( RS_HEX_5 );
|
||||
input[ 7 ] = mMessage.getInt( RS_HEX_4 );
|
||||
input[ 8 ] = mMessage.getInt( RS_HEX_3 );
|
||||
input[ 9 ] = mMessage.getInt( RS_HEX_2 );
|
||||
input[ 10 ] = mMessage.getInt( RS_HEX_1 );
|
||||
input[ 11 ] = mMessage.getInt( RS_HEX_0 );
|
||||
|
||||
input[ 12 ] = mMessage.getInt( CW_HEX_11 );
|
||||
input[ 13 ] = mMessage.getInt( CW_HEX_10 );
|
||||
input[ 14 ] = mMessage.getInt( CW_HEX_9 );
|
||||
input[ 15 ] = mMessage.getInt( CW_HEX_8 );
|
||||
input[ 16 ] = mMessage.getInt( CW_HEX_7 );
|
||||
input[ 17 ] = mMessage.getInt( CW_HEX_6 );
|
||||
input[ 18 ] = mMessage.getInt( CW_HEX_5 );
|
||||
input[ 19 ] = mMessage.getInt( CW_HEX_4 );
|
||||
input[ 20 ] = mMessage.getInt( CW_HEX_3 );
|
||||
input[ 21 ] = mMessage.getInt( CW_HEX_2 );
|
||||
input[ 22 ] = mMessage.getInt( CW_HEX_1 );
|
||||
input[ 23 ] = mMessage.getInt( CW_HEX_0 );
|
||||
int[] input = new int[63];
|
||||
int[] output = new int[63];
|
||||
|
||||
input[0] = mMessage.getInt(RS_HEX_11);
|
||||
input[1] = mMessage.getInt(RS_HEX_10);
|
||||
input[2] = mMessage.getInt(RS_HEX_9);
|
||||
input[3] = mMessage.getInt(RS_HEX_8);
|
||||
input[4] = mMessage.getInt(RS_HEX_7);
|
||||
input[5] = mMessage.getInt(RS_HEX_6);
|
||||
input[6] = mMessage.getInt(RS_HEX_5);
|
||||
input[7] = mMessage.getInt(RS_HEX_4);
|
||||
input[8] = mMessage.getInt(RS_HEX_3);
|
||||
input[9] = mMessage.getInt(RS_HEX_2);
|
||||
input[10] = mMessage.getInt(RS_HEX_1);
|
||||
input[11] = mMessage.getInt(RS_HEX_0);
|
||||
|
||||
input[12] = mMessage.getInt(CW_HEX_11);
|
||||
input[13] = mMessage.getInt(CW_HEX_10);
|
||||
input[14] = mMessage.getInt(CW_HEX_9);
|
||||
input[15] = mMessage.getInt(CW_HEX_8);
|
||||
input[16] = mMessage.getInt(CW_HEX_7);
|
||||
input[17] = mMessage.getInt(CW_HEX_6);
|
||||
input[18] = mMessage.getInt(CW_HEX_5);
|
||||
input[19] = mMessage.getInt(CW_HEX_4);
|
||||
input[20] = mMessage.getInt(CW_HEX_3);
|
||||
input[21] = mMessage.getInt(CW_HEX_2);
|
||||
input[22] = mMessage.getInt(CW_HEX_1);
|
||||
input[23] = mMessage.getInt(CW_HEX_0);
|
||||
/* indexes 24 - 62 are defaulted to zero */
|
||||
|
||||
boolean irrecoverableErrors = mReedSolomonDecoder.decode( input, output );
|
||||
boolean irrecoverableErrors = mReedSolomonDecoder.decode(input, output);
|
||||
|
||||
if( irrecoverableErrors )
|
||||
if(irrecoverableErrors)
|
||||
{
|
||||
mCRC[ 2 ] = CRC.FAILED_CRC;
|
||||
mCRC[2] = CRC.FAILED_CRC;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Since we've detected that we can correct the RS words, mark the
|
||||
* hamming crc as corrected as well, if it is currently failed */
|
||||
if( mCRC[ 1 ] == CRC.FAILED_CRC )
|
||||
{
|
||||
mCRC[ 1 ] = CRC.CORRECTED;
|
||||
}
|
||||
|
||||
mCRC[ 2 ] = CRC.PASSED;
|
||||
if(mCRC[1] == CRC.FAILED_CRC)
|
||||
{
|
||||
mCRC[1] = CRC.CORRECTED;
|
||||
}
|
||||
|
||||
mCRC[2] = CRC.PASSED;
|
||||
|
||||
/* Only fix the codeword data hex codewords */
|
||||
repairHexCodeword( input, output, 12, CW_HEX_11 );
|
||||
repairHexCodeword( input, output, 13, CW_HEX_10 );
|
||||
repairHexCodeword( input, output, 14, CW_HEX_9 );
|
||||
repairHexCodeword( input, output, 15, CW_HEX_8 );
|
||||
repairHexCodeword( input, output, 16, CW_HEX_7 );
|
||||
repairHexCodeword( input, output, 17, CW_HEX_6 );
|
||||
repairHexCodeword( input, output, 18, CW_HEX_5 );
|
||||
repairHexCodeword( input, output, 19, CW_HEX_4 );
|
||||
repairHexCodeword( input, output, 20, CW_HEX_3 );
|
||||
repairHexCodeword( input, output, 21, CW_HEX_2 );
|
||||
repairHexCodeword( input, output, 22, CW_HEX_1 );
|
||||
repairHexCodeword( input, output, 23, CW_HEX_0 );
|
||||
repairHexCodeword(input, output, 12, CW_HEX_11);
|
||||
repairHexCodeword(input, output, 13, CW_HEX_10);
|
||||
repairHexCodeword(input, output, 14, CW_HEX_9);
|
||||
repairHexCodeword(input, output, 15, CW_HEX_8);
|
||||
repairHexCodeword(input, output, 16, CW_HEX_7);
|
||||
repairHexCodeword(input, output, 17, CW_HEX_6);
|
||||
repairHexCodeword(input, output, 18, CW_HEX_5);
|
||||
repairHexCodeword(input, output, 19, CW_HEX_4);
|
||||
repairHexCodeword(input, output, 20, CW_HEX_3);
|
||||
repairHexCodeword(input, output, 21, CW_HEX_2);
|
||||
repairHexCodeword(input, output, 22, CW_HEX_1);
|
||||
repairHexCodeword(input, output, 23, CW_HEX_0);
|
||||
}
|
||||
}
|
||||
|
||||
private void repairHexCodeword( int[] input, int[] output, int index, int[] indexSet )
|
||||
{
|
||||
if( input[ index ] != output[ index ] )
|
||||
{
|
||||
mMessage.load( indexSet[ 0 ], 6, output[ index ] );
|
||||
mCRC[ 2 ] = CRC.CORRECTED;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( getMessageStub() );
|
||||
sb.append( " " );
|
||||
sb.append( mMessage.toString() );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getMessageStub()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( super.getMessageStub() );
|
||||
|
||||
if( isEncrypted() )
|
||||
{
|
||||
sb.append( "ENCRYPTED" );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( isImplicitFormat() || getVendor() == Vendor.STANDARD )
|
||||
{
|
||||
sb.append( getOpcode().getLabel() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "VENDOR:" + getVendor().getLabel() + " " );
|
||||
sb.append( getVendorOpcode().getLabel() );
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public boolean isImplicitFormat()
|
||||
{
|
||||
return mMessage.get( IMPLICIT_VENDOR_FLAG );
|
||||
}
|
||||
|
||||
public LinkControlOpcode getOpcode()
|
||||
{
|
||||
return LinkControlOpcode.fromValue( mMessage.getInt( OPCODE ) );
|
||||
}
|
||||
private void repairHexCodeword(int[] input, int[] output, int index, int[] indexSet)
|
||||
{
|
||||
if(input[index] != output[index])
|
||||
{
|
||||
mMessage.load(indexSet[0], 6, output[index]);
|
||||
mCRC[2] = CRC.CORRECTED;
|
||||
}
|
||||
}
|
||||
|
||||
public VendorLinkControlOpcode getVendorOpcode()
|
||||
{
|
||||
return VendorLinkControlOpcode.fromValue( mMessage.getInt( OPCODE ) );
|
||||
}
|
||||
|
||||
public Vendor getVendor()
|
||||
{
|
||||
if( isImplicitFormat() )
|
||||
{
|
||||
return Vendor.STANDARD;
|
||||
}
|
||||
|
||||
return Vendor.fromValue( mMessage.getInt( VENDOR ) );
|
||||
}
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(getMessageStub());
|
||||
sb.append(" ");
|
||||
sb.append(mMessage.toString());
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getMessageStub()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(super.getMessageStub());
|
||||
|
||||
if(isEncryptedLinkControlWord())
|
||||
{
|
||||
sb.append("ENCRYPTED");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isImplicitFormat() || getVendor() == Vendor.STANDARD)
|
||||
{
|
||||
sb.append(getOpcode().getLabel());
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("VENDOR:" + getVendor().getLabel() + " ");
|
||||
sb.append(getVendorOpcode().getLabel());
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public boolean isImplicitFormat()
|
||||
{
|
||||
return mMessage.get(IMPLICIT_VENDOR_FLAG);
|
||||
}
|
||||
|
||||
public LinkControlOpcode getOpcode()
|
||||
{
|
||||
return LinkControlOpcode.fromValue(mMessage.getInt(OPCODE));
|
||||
}
|
||||
|
||||
public VendorLinkControlOpcode getVendorOpcode()
|
||||
{
|
||||
return VendorLinkControlOpcode.fromValue(mMessage.getInt(OPCODE));
|
||||
}
|
||||
|
||||
public Vendor getVendor()
|
||||
{
|
||||
if(isImplicitFormat())
|
||||
{
|
||||
return Vendor.STANDARD;
|
||||
}
|
||||
|
||||
return Vendor.fromValue(mMessage.getInt(VENDOR));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,9 +72,11 @@ public class LDU2Message extends LDUMessage
|
||||
|
||||
checkCRC();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEncrypted()
|
||||
|
||||
/**
|
||||
* Indicates if the audio stream is encrypted
|
||||
*/
|
||||
public boolean isEncryptedAudio()
|
||||
{
|
||||
Encryption encryption = getEncryption();
|
||||
|
||||
|
||||
@@ -35,8 +35,6 @@ public abstract class LDUMessage extends P25Message
|
||||
super( message, duid, aliasList );
|
||||
}
|
||||
|
||||
public abstract boolean isEncrypted();
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@ public class IdentifierUpdateTDMA extends IdentifierUpdate
|
||||
|
||||
sb.append( " ID:" + getIdentifier() );
|
||||
sb.append( " BASE:" + getBaseFrequency() );
|
||||
sb.append( " BW:" + getBandwidth() );
|
||||
sb.append( " BANDWIDTH:" + getBandwidth() );
|
||||
sb.append( " SPACING:" + getChannelSpacing() );
|
||||
sb.append( " OFFSET:" + getTransmitOffset() );
|
||||
sb.append( " TYPE:" + getChannelType().toString() );
|
||||
@@ -137,7 +137,7 @@ public class IdentifierUpdateTDMA extends IdentifierUpdate
|
||||
|
||||
sb.append( mAccessType.name() );
|
||||
sb.append( " BANDWIDTH:" + mBandwidth );
|
||||
sb.append( " SLOT/CARRIER:" + mSlotsPerCarrier );
|
||||
sb.append( " TIMESLOTS PER CARRIER:" + mSlotsPerCarrier );
|
||||
sb.append( " VOCODER:" + mVocoder.name() );
|
||||
|
||||
return sb.toString();
|
||||
|
||||
Reference in New Issue
Block a user