#1304 P25 Phase 1/2 decoder enhancements. (#1898)

* P25 Phase 2 now supports control channel decoding and decoder was enhanced to improve decodes.
* Radio reference site editor updated for phase 2 sites to allow user to select FDMA or TDMA control.
* Decode events are now minimized and de-duplicated.
* Fully parsing all phase 1/2 messages from the latest ICD.
* Vendor specific messaging recoveries (Moto & Harris).
* Patch group management enhancements with stale patch detection.
* Tuner editor now fully resets the min/max frequency values
* Default traffic channel count increased to 20 (from 3).
* ISSI roaming radio and talkgroup values now displayed and aliasable as fully qualified values (e.g. 1234(123.456.7890)
* Moto emergency alarm activation messaging support
* Expanded list of P25 encryption algorithms
* Message (bits) viewer enhanced for P25 phase 1 and phase 2
* IPV4 addresses and UDP ports no longer classified as user values - won't display in event views.
* New framework for describing message binary fields that should reduce overall memory footprint and enhance code readability

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
Denny Sheirer
2024-04-26 13:55:17 -04:00
committed by GitHub
parent f5938fa8e2
commit 7e709d9d6f
430 changed files with 30098 additions and 13300 deletions

View File

@@ -32,6 +32,7 @@ import io.github.dsheirer.controller.channel.map.ChannelMapModel;
import io.github.dsheirer.filter.AllPassFilter;
import io.github.dsheirer.filter.FilterSet;
import io.github.dsheirer.filter.IFilter;
import io.github.dsheirer.identifier.patch.PatchGroupManager;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.message.MessageDirection;
import io.github.dsheirer.module.Module;
@@ -51,6 +52,7 @@ import io.github.dsheirer.module.decode.dmr.audio.DMRAudioModule;
import io.github.dsheirer.module.decode.dmr.channel.DMRChannel;
import io.github.dsheirer.module.decode.dmr.channel.DMRLsn;
import io.github.dsheirer.module.decode.dmr.channel.DmrRestLsn;
import io.github.dsheirer.module.decode.dmr.message.DMRMessage;
import io.github.dsheirer.module.decode.dmr.message.filter.DmrMessageFilterSet;
import io.github.dsheirer.module.decode.event.DecodeEvent;
import io.github.dsheirer.module.decode.fleetsync2.Fleetsync2Decoder;
@@ -90,6 +92,7 @@ import io.github.dsheirer.module.decode.p25.phase1.message.filter.P25P1MessageFi
import io.github.dsheirer.module.decode.p25.phase2.DecodeConfigP25Phase2;
import io.github.dsheirer.module.decode.p25.phase2.P25P2DecoderHDQPSK;
import io.github.dsheirer.module.decode.p25.phase2.P25P2DecoderState;
import io.github.dsheirer.module.decode.p25.phase2.message.P25P2Message;
import io.github.dsheirer.module.decode.p25.phase2.message.filter.P25P2MessageFilterSet;
import io.github.dsheirer.module.decode.passport.DecodeConfigPassport;
import io.github.dsheirer.module.decode.passport.PassportDecoder;
@@ -149,7 +152,7 @@ public class DecoderFactory
UserPreferences userPreferences, TrafficChannelManager trafficChannelManager,
IChannelDescriptor channelDescriptor)
{
List<Module> modules = new ArrayList<Module>();
List<Module> modules = new ArrayList<>();
AliasList aliasList = aliasModel.getAliasList(channel.getAliasListName());
modules.add(new AliasActionManager(aliasList));
@@ -178,7 +181,8 @@ public class DecoderFactory
processLTRNet(channel, modules, aliasList, (DecodeConfigLTRNet) decodeConfig);
break;
case MPT1327:
processMPT1327(channelMapModel, channel, modules, aliasList, channelType, (DecodeConfigMPT1327) decodeConfig);
processMPT1327(channelMapModel, channel, modules, aliasList, channelType,
(DecodeConfigMPT1327) decodeConfig, userPreferences);
break;
case PASSPORT:
processPassport(channel, modules, aliasList, decodeConfig);
@@ -187,7 +191,7 @@ public class DecoderFactory
processP25Phase1(channel, userPreferences, modules, aliasList, channelType, (DecodeConfigP25Phase1) decodeConfig);
break;
case P25_PHASE2:
processP25Phase2(channel, userPreferences, modules, aliasList);
processP25Phase2(channel, userPreferences, modules, aliasList, trafficChannelManager);
break;
default:
throw new IllegalArgumentException("Unknown decoder type [" + decodeConfig.getDecoderType().toString() + "]");
@@ -202,14 +206,53 @@ public class DecoderFactory
* @param userPreferences reference
* @param modules collection to add to
* @param aliasList for the channel
* @param trafficChannelManager from parent, if this is for a traffic channel, otherwise this can be null and it
* will be created automatically.
*/
private static void processP25Phase2(Channel channel, UserPreferences userPreferences, List<Module> modules, AliasList aliasList) {
private static void processP25Phase2(Channel channel, UserPreferences userPreferences, List<Module> modules,
AliasList aliasList, TrafficChannelManager trafficChannelManager)
{
modules.add(new P25P2DecoderHDQPSK((DecodeConfigP25Phase2)channel.getDecodeConfiguration()));
modules.add(new P25P2DecoderState(channel, 0));
modules.add(new P25P2DecoderState(channel, 1));
modules.add(new P25P2AudioModule(userPreferences, 0, aliasList));
modules.add(new P25P2AudioModule(userPreferences, 1, aliasList));
P25TrafficChannelManager p25TrafficChannelManager = null;
if(channel.getChannelType() == ChannelType.STANDARD)
{
p25TrafficChannelManager = new P25TrafficChannelManager(channel);
}
else if(trafficChannelManager instanceof P25TrafficChannelManager p25)
{
p25TrafficChannelManager = p25;
}
else
{
p25TrafficChannelManager = new P25TrafficChannelManager(channel);
}
//Only add traffic channel manager to the modules if this is the control channel
if(channel.isStandardChannel())
{
modules.add(p25TrafficChannelManager);
}
PatchGroupManager patchGroupManager = new PatchGroupManager();
modules.add(new P25P2DecoderState(channel, P25P2Message.TIMESLOT_1, p25TrafficChannelManager, patchGroupManager));
modules.add(new P25P2DecoderState(channel, P25P2Message.TIMESLOT_2, p25TrafficChannelManager, patchGroupManager));
modules.add(new P25P2AudioModule(userPreferences, P25P2Message.TIMESLOT_1, aliasList));
modules.add(new P25P2AudioModule(userPreferences, P25P2Message.TIMESLOT_2, aliasList));
//Add a channel rotation monitor when we have multiple control channel frequencies specified
if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency &&
((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).hasMultipleFrequencies())
{
List<State> activeStates = new ArrayList<>();
activeStates.add(State.CONTROL);
modules.add(new ChannelRotationMonitor(activeStates,
((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).getFrequencyRotationDelay(),
userPreferences));
}
}
/**
@@ -219,7 +262,8 @@ public class DecoderFactory
* @param modules collection to add to
* @param aliasList for the channel
*/
private static void processP25Phase1(Channel channel, UserPreferences userPreferences, List<Module> modules, AliasList aliasList, ChannelType channelType, DecodeConfigP25Phase1 decodeConfig) {
private static void processP25Phase1(Channel channel, UserPreferences userPreferences, List<Module> modules, AliasList aliasList, ChannelType channelType, DecodeConfigP25Phase1 decodeConfig)
{
DecodeConfigP25Phase1 p25Config = decodeConfig;
switch(p25Config.getModulation())
@@ -249,13 +293,12 @@ public class DecoderFactory
modules.add(new P25P1AudioModule(userPreferences, aliasList));
//Add a channel rotation monitor when we have multiple control channel frequencies specified
if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency &&
((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).hasMultipleFrequencies())
if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency sctmf &&
sctmf.hasMultipleFrequencies())
{
List<State> activeStates = new ArrayList<>();
activeStates.add(State.CONTROL);
modules.add(new ChannelRotationMonitor(activeStates,
((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).getFrequencyRotationDelay()));
modules.add(new ChannelRotationMonitor(activeStates, sctmf.getFrequencyRotationDelay(), userPreferences));
}
}
@@ -285,7 +328,10 @@ public class DecoderFactory
* @param channelType for control or traffic
* @param decodeConfig configuration
*/
private static void processMPT1327(ChannelMapModel channelMapModel, Channel channel, List<Module> modules, AliasList aliasList, ChannelType channelType, DecodeConfigMPT1327 decodeConfig) {
private static void processMPT1327(ChannelMapModel channelMapModel, Channel channel, List<Module> modules,
AliasList aliasList, ChannelType channelType, DecodeConfigMPT1327 decodeConfig,
UserPreferences userPreferences)
{
DecodeConfigMPT1327 mptConfig = decodeConfig;
ChannelMap channelMap = channelMapModel.getChannelMap(mptConfig.getChannelMapName());
Sync sync = mptConfig.getSync();
@@ -317,13 +363,12 @@ public class DecoderFactory
}
//Add a channel rotation monitor when we have multiple control channel frequencies specified
if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency &&
((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).hasMultipleFrequencies())
if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency sctmf &&
sctmf.hasMultipleFrequencies())
{
List<State> activeStates = new ArrayList<>();
activeStates.add(State.CONTROL);
modules.add(new ChannelRotationMonitor(activeStates,
((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).getFrequencyRotationDelay()));
modules.add(new ChannelRotationMonitor(activeStates, sctmf.getFrequencyRotationDelay(), userPreferences));
}
}
@@ -440,8 +485,8 @@ public class DecoderFactory
modules.add(dmrTrafficChannelManager);
}
DMRDecoderState state1 = new DMRDecoderState(channel, 1, dmrTrafficChannelManager);
DMRDecoderState state2 = new DMRDecoderState(channel, 2, dmrTrafficChannelManager);
DMRDecoderState state1 = new DMRDecoderState(channel, DMRMessage.TIMESLOT_1, dmrTrafficChannelManager);
DMRDecoderState state2 = new DMRDecoderState(channel, DMRMessage.TIMESLOT_2, dmrTrafficChannelManager);
//Register the states with each other so that they can pass Cap+ site status messaging to resolve current channel
state1.setSisterDecoderState(state2);
@@ -457,7 +502,7 @@ public class DecoderFactory
lsn.setTimeslotFrequency(rest.getTimeslotFrequency());
}
if(lsn.getTimeslot() == 1)
if(lsn.getTimeslot() == DMRMessage.TIMESLOT_1)
{
state1.setCurrentChannel(lsn);
state2.setCurrentChannel(lsn.getSisterTimeslot());
@@ -473,7 +518,7 @@ public class DecoderFactory
{
DecodeEvent event = decodeConfig.getChannelGrantEvent();
if(decodeConfig.getChannelGrantEvent().getTimeslot() == 1)
if(decodeConfig.getChannelGrantEvent().getTimeslot() == DMRMessage.TIMESLOT_1)
{
state1.setCurrentCallEvent(event);
@@ -495,17 +540,16 @@ public class DecoderFactory
modules.add(state1);
modules.add(state2);
modules.add(new DMRAudioModule(userPreferences, aliasList, 1));
modules.add(new DMRAudioModule(userPreferences, aliasList, 2));
modules.add(new DMRAudioModule(userPreferences, aliasList, DMRMessage.TIMESLOT_1));
modules.add(new DMRAudioModule(userPreferences, aliasList, DMRMessage.TIMESLOT_2));
//Add a channel rotation monitor when we have multiple control channel frequencies specified
if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency &&
((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).hasMultipleFrequencies())
if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency sctmf &&
sctmf.hasMultipleFrequencies())
{
List<State> activeStates = new ArrayList<>();
activeStates.add(State.CONTROL);
modules.add(new ChannelRotationMonitor(activeStates,
((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).getFrequencyRotationDelay()));
modules.add(new ChannelRotationMonitor(activeStates, sctmf.getFrequencyRotationDelay(), userPreferences));
}
}

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.config;
@@ -34,8 +31,7 @@ import io.github.dsheirer.module.decode.ltrnet.DecodeConfigLTRNet;
import io.github.dsheirer.module.decode.ltrstandard.DecodeConfigLTRStandard;
import io.github.dsheirer.module.decode.mpt1327.DecodeConfigMPT1327;
import io.github.dsheirer.module.decode.nbfm.DecodeConfigNBFM;
import io.github.dsheirer.module.decode.p25.phase1.DecodeConfigP25Phase1;
import io.github.dsheirer.module.decode.p25.phase2.DecodeConfigP25Phase2;
import io.github.dsheirer.module.decode.p25.phase1.DecodeConfigP25;
import io.github.dsheirer.module.decode.passport.DecodeConfigPassport;
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
@@ -47,10 +43,9 @@ import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
@JsonSubTypes.Type(value = DecodeConfigLTRStandard.class, name = "decodeConfigLTRStandard"),
@JsonSubTypes.Type(value = DecodeConfigMPT1327.class, name = "decodeConfigMPT1327"),
@JsonSubTypes.Type(value = DecodeConfigNBFM.class, name = "decodeConfigNBFM"),
@JsonSubTypes.Type(value = DecodeConfigP25Phase1.class, name = "decodeConfigP25Phase1"),
@JsonSubTypes.Type(value = DecodeConfigP25Phase2.class, name = "decodeConfigP25Phase2"),
@JsonSubTypes.Type(value = DecodeConfigP25.class, name = "decodeConfigP25"),
@JsonSubTypes.Type(value = DecodeConfigPassport.class, name = "decodeConfigPassport"),
@JsonSubTypes.Type(value = DecodeConfigDMR.class, name = "decodeConfigDMR")
@JsonSubTypes.Type(value = DecodeConfigDMR.class, name = "decodeConfigDMR")
})
@JacksonXmlRootElement(localName = "decode_configuration")
public abstract class DecodeConfiguration extends Configuration
@@ -58,10 +53,7 @@ public abstract class DecodeConfiguration extends Configuration
public static final int DEFAULT_CALL_TIMEOUT_DELAY_SECONDS = 45;
public static final int CALL_TIMEOUT_MINIMUM = 1;
public static final int CALL_TIMEOUT_MAXIMUM = 180;
public static final int TRAFFIC_CHANNEL_LIMIT_DEFAULT = 3;
public static final int TRAFFIC_CHANNEL_LIMIT_MINIMUM = 0;
public static final int TRAFFIC_CHANNEL_LIMIT_MAXIMUM = 30;
public static final int TRAFFIC_CHANNEL_LIMIT_DEFAULT = 20;
public DecodeConfiguration()
{

View File

@@ -124,7 +124,6 @@ public class DMRDecoderState extends TimeslotDecoderState
private DMRNetworkConfigurationMonitor mNetworkConfigurationMonitor;
private DMRTrafficChannelManager mTrafficChannelManager;
private DecodeEvent mCurrentCallEvent;
private long mCurrentFrequency;
private boolean mIgnoreCRCChecksums;
private DMRDecoderState mSisterDecoderState;
@@ -275,8 +274,7 @@ public class DMRDecoderState extends TimeslotDecoderState
{
super.reset();
resetState();
mCurrentFrequency = 0;
setCurrentFrequency(0);
}
/**
@@ -347,11 +345,11 @@ public class DMRDecoderState extends TimeslotDecoderState
private void updateRestChannel(DMRChannel restChannel)
{
//Only respond if this is a standard/control channel (not a traffic channel).
if(mChannel.isStandardChannel() && mCurrentFrequency > 0 &&
if(mChannel.isStandardChannel() && getCurrentFrequency() > 0 &&
restChannel.getDownlinkFrequency() > 0 &&
restChannel.getDownlinkFrequency() != mCurrentFrequency && mTrafficChannelManager != null)
restChannel.getDownlinkFrequency() != getCurrentFrequency() && mTrafficChannelManager != null)
{
mTrafficChannelManager.convertToTrafficChannel(mChannel, mCurrentFrequency, restChannel,
mTrafficChannelManager.convertToTrafficChannel(mChannel, getCurrentFrequency(), restChannel,
mNetworkConfigurationMonitor);
}
}
@@ -1400,9 +1398,9 @@ public class DMRDecoderState extends TimeslotDecoderState
Event event = (mCurrentCallEvent == null ? Event.START : Event.CONTINUATION);
//Create a repeater channel descriptor if we don't have one
if(mCurrentChannel == null && mCurrentFrequency > 0)
if(mCurrentChannel == null && getCurrentFrequency() > 0)
{
mCurrentChannel = new DMRAbsoluteChannel(getTimeslot(), getTimeslot(), mCurrentFrequency, 0);
mCurrentChannel = new DMRAbsoluteChannel(getTimeslot(), getTimeslot(), getCurrentFrequency(), 0);
}
if(mCurrentCallEvent == null)
@@ -1475,11 +1473,12 @@ public class DMRDecoderState extends TimeslotDecoderState
resetState();
break;
case NOTIFICATION_SOURCE_FREQUENCY:
long previous = mCurrentFrequency;
mCurrentFrequency = event.getFrequency();
if(hasTrafficChannelManager())
setCurrentFrequency(event.getFrequency());
//Only update the traffic channel manager if we're not a traffic channel.
if(hasTrafficChannelManager() && mChannel.isStandardChannel())
{
mTrafficChannelManager.setCurrentControlFrequency(previous, mCurrentFrequency, mChannel);
mTrafficChannelManager.setCurrentControlFrequency(getCurrentFrequency(), mChannel);
}
break;
default:

View File

@@ -132,13 +132,13 @@ public class DMRTrafficChannelManager extends TrafficChannelManager implements I
/**
* Sets the current parent control channel frequency so that channel grants for the current frequency do not
* produce an additional traffic channel allocation.
* @param previousControlFrequency for the current control channel (to remove from allocated channels)
* @param currentControlFrequency for current control channel (to add to allocated channels)
* @param previous for the current control channel (to remove from allocated channels)
* @param current for current control channel (to add to allocated channels)
* @param channel for the current control channel
*/
public void setCurrentControlFrequency(long previousControlFrequency, long currentControlFrequency, Channel channel)
public void processControlFrequencyUpdate(long previous, long current, Channel channel)
{
if(previousControlFrequency == currentControlFrequency)
if(previous == current)
{
return;
}
@@ -147,18 +147,18 @@ public class DMRTrafficChannelManager extends TrafficChannelManager implements I
try
{
Channel existing = mAllocatedChannelFrequencyMap.get(previousControlFrequency);
Channel existing = mAllocatedChannelFrequencyMap.get(previous);
//Only remove the channel if it is non-null and it matches the current control channel.
if(channel.equals(existing))
{
//Unlock the frequency in the channel rotation monitor
getInterModuleEventBus().post(FrequencyLockChangeRequest.unlock(previousControlFrequency));
mAllocatedChannelFrequencyMap.remove(previousControlFrequency);
getInterModuleEventBus().post(FrequencyLockChangeRequest.unlock(previous));
mAllocatedChannelFrequencyMap.remove(previous);
}
mAllocatedChannelFrequencyMap.put(currentControlFrequency, channel);
getInterModuleEventBus().post(FrequencyLockChangeRequest.lock(currentControlFrequency));
mAllocatedChannelFrequencyMap.put(current, channel);
getInterModuleEventBus().post(FrequencyLockChangeRequest.lock(current));
}
finally
{

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.module.decode.dmr.channel.TimeslotFrequency;
import io.github.dsheirer.module.decode.dmr.message.DMRMessage;
import io.github.dsheirer.module.decode.event.DecodeEvent;
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
import java.util.ArrayList;
@@ -64,10 +65,7 @@ public class DecodeConfigDMR extends DecodeConfiguration
@Override
public int[] getTimeslots()
{
int[] timeslots = new int[2];
timeslots[0] = 1;
timeslots[1] = 2;
return timeslots;
return new int[]{DMRMessage.TIMESLOT_1, DMRMessage.TIMESLOT_2};
}
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,6 +28,9 @@ import io.github.dsheirer.protocol.Protocol;
*/
public abstract class DMRMessage extends Message
{
public static final int TIMESLOT_1 = 1;
public static final int TIMESLOT_2 = 2;
private CorrectedBinaryMessage mCorrectedBinaryMessage;
private boolean mValid = true;
private int mTimeslot;

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,6 +50,28 @@ public class DecodeEvent implements IDecodeEvent
mTimeStart = start;
}
/**
* Sets or changes the decode event type.
* @param type to set.
*/
public void setDecodeEventType(DecodeEventType type)
{
if(type == null)
{
throw new IllegalArgumentException("Decode event type cannot be null");
}
mDecodeEventType = type;
}
/**
* Creates a snapshot of this decode event for offline analysis
*/
public DecodeEventSnapshot getSnapshot()
{
return new DecodeEventSnapshot(this);
}
/**
* Creates a new decode event builder with the specified start timestamp.
* @param decodeEventType for the event
@@ -238,7 +260,8 @@ public class DecodeEvent implements IDecodeEvent
sb.append(" IDS:").append(Joiner.on(",").join(mIdentifierCollection.getIdentifiers()));
}
sb.append(" DURATION:").append(getDuration());
sb.append(" CHANNEL:").append(mChannelDescriptor);
sb.append(" CHANNEL:").append(getChannelDescriptor());
sb.append(" TIMESLOT:").append(getTimeslot());
return sb.toString();
}

View File

@@ -0,0 +1,136 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.event;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Provides duplicate decode event detection support
*/
public class DecodeEventDuplicateDetector
{
private static final long EVENT_MAX_AGE_MILLISECONDS = Duration.ofMinutes(1).toMillis();
private Map<DecodeEventType,DecodeEventTracker> mTrackerMap = new HashMap<>();
/**
* Indicates if the event is a duplicate event.
* @param event to check
* @param timestamp of a current message to trigger time-based event age off.
* @return true if the event is a duplicate.
*/
public synchronized boolean isDuplicate(IDecodeEvent event, long timestamp)
{
//Null event types and voice call event types are not tracked by this detector
if(event.getEventType() == null || event.getEventType().isVoiceCallEvent())
{
return false;
}
if(!mTrackerMap.containsKey(event.getEventType()))
{
mTrackerMap.put(event.getEventType(), new DecodeEventTracker());
}
boolean duplicate = mTrackerMap.get(event.getEventType()).isDuplicate(event);
for(DecodeEventTracker tracker: mTrackerMap.values())
{
tracker.ageOff(timestamp);
}
return duplicate;
}
/**
* Tracks all decode events for a given decode event type
*/
private class DecodeEventTracker
{
private Map<String,IDecodeEvent> mDecodeEventMap = new HashMap<>();
/**
* Checks the event for duplicate
* @param event to check
* @return true if duplicate
*/
public boolean isDuplicate(IDecodeEvent event)
{
if(event.getIdentifierCollection().getToIdentifier() == null || event.getDetails() == null)
{
return false;
}
String key = getKey(event);
if(key == null || key.isEmpty())
{
return false;
}
if(mDecodeEventMap.containsKey(key))
{
return true;
}
else
{
mDecodeEventMap.put(key, event);
}
return false;
}
/**
* Generates a unique event key that is a combinatio of the TO identifier value and the details of the event.
* @param event for the key
* @return generated key.
*/
private static String getKey(IDecodeEvent event)
{
return event.getIdentifierCollection().getToIdentifier().toString() + event.getDetails();
}
/**
* Removes all decode events from the duplicate detection map that are too old.
* @param timestamp for the current messaging.
*/
public void ageOff(long timestamp)
{
long threshold = timestamp - EVENT_MAX_AGE_MILLISECONDS;
List<String> toRemove = new ArrayList<>();
for(Map.Entry<String,IDecodeEvent> entry: mDecodeEventMap.entrySet())
{
if(entry.getValue() == null || entry.getValue().getTimeStart() < threshold)
{
toRemove.add(entry.getKey());
}
}
for(String key: toRemove)
{
mDecodeEventMap.remove(key);
}
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -115,9 +115,9 @@ public class DecodeEventModel extends ClearableHistoryModel<IDecodeEvent> implem
if(channelDescriptor != null)
{
if(event.hasTimeslot())
if(event.hasTimeslot() && !event.toString().contains("TS"))
{
return channelDescriptor + " TS:" + event.getTimeslot();
return channelDescriptor + " TS" + event.getTimeslot();
}
else
{
@@ -126,9 +126,9 @@ public class DecodeEventModel extends ClearableHistoryModel<IDecodeEvent> implem
}
else
{
if(event.hasTimeslot())
if(event.hasTimeslot() && !event.toString().contains("TS"))
{
return "TS:" + event.getTimeslot();
return "TS" + event.getTimeslot();
}
else
{

View File

@@ -0,0 +1,50 @@
package io.github.dsheirer.module.decode.event;
import io.github.dsheirer.identifier.IdentifierCollection;
/**
* Snapshot of a decode event that also preserves the object instance hash code.
*/
public class DecodeEventSnapshot extends DecodeEvent
{
private int mOriginalHashCode;
/**
* Constructs an instance
*
* @param decodeEvent to snapshot
*/
public DecodeEventSnapshot(DecodeEvent decodeEvent)
{
super(decodeEvent.getEventType(), decodeEvent.getTimeStart());
mOriginalHashCode = decodeEvent.hashCode();
setDetails(decodeEvent.getDetails());
setDuration(decodeEvent.getDuration());
setProtocol(decodeEvent.getProtocol());
setTimeslot(decodeEvent.getTimeslot());
setChannelDescriptor(decodeEvent.getChannelDescriptor());
if(decodeEvent.getIdentifierCollection() != null)
{
setIdentifierCollection(new IdentifierCollection(decodeEvent.getIdentifierCollection().getIdentifiers()));
}
}
/**
* Hashcode of the original decode event for this snapshot (not this snapshot instance's hash code).
* @return
*/
public int getOriginalHashCode()
{
return mOriginalHashCode;
}
/**
* Frequency for the channel descriptor
* @return frequency or zero.
*/
public long getFrequency()
{
return getChannelDescriptor() != null ? getChannelDescriptor().getDownlinkFrequency() : 0;
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -55,6 +55,7 @@ public enum DecodeEventType
DATA_CALL_ENCRYPTED("Encrypted Data Call"),
DATA_PACKET("Data Packet"),
DEREGISTER("Deregister"),
DYNAMIC_REGROUP("Dynamic Regroup"),
EMERGENCY("EMERGENCY"),
FUNCTION("Function"),
GPS("GPS"),
@@ -106,7 +107,7 @@ public enum DecodeEventType
public static final EnumSet<DecodeEventType> COMMANDS = EnumSet.of(DecodeEventType.ANNOUNCEMENT,
DecodeEventType.STATION_ID, DecodeEventType.ACKNOWLEDGE, DecodeEventType.PAGE, DecodeEventType.QUERY,
DecodeEventType.RADIO_CHECK, DecodeEventType.STATUS, DecodeEventType.COMMAND, DecodeEventType.EMERGENCY,
DecodeEventType.NOTIFICATION, DecodeEventType.FUNCTION);
DecodeEventType.NOTIFICATION, DecodeEventType.FUNCTION, DecodeEventType.DYNAMIC_REGROUP);
/**
* Data call event types for filtering
@@ -129,6 +130,13 @@ public enum DecodeEventType
public static final EnumSet<DecodeEventType> OTHERS = EnumSet.copyOf(Arrays.stream(DecodeEventType.values())
.filter(decodeEventType -> !decodeEventType.isGrouped()).toList());
/**
* Voice call event types.
*/
public static final EnumSet<DecodeEventType> VOICE_CALL_EVENTS = EnumSet.of(CALL, CALL_ENCRYPTED, CALL_GROUP,
CALL_GROUP_ENCRYPTED, CALL_PATCH_GROUP, CALL_PATCH_GROUP_ENCRYPTED, CALL_INTERCONNECT,
CALL_INTERCONNECT_ENCRYPTED, CALL_UNIT_TO_UNIT, CALL_UNIT_TO_UNIT_ENCRYPTED);
/**
* Constructor
* @param label for the element
@@ -149,12 +157,12 @@ public enum DecodeEventType
}
/**
* Indicates if this is a call event.
* @return true if this is a call event type.
* Indicates if this is a voice call event.
* @return true if this is a voice call event type.
*/
public boolean isCallEvent()
public boolean isVoiceCallEvent()
{
return VOICE_CALLS.contains(this) || VOICE_CALLS_ENCRYPTED.contains(this) || DATA_CALLS.contains(this);
return VOICE_CALL_EVENTS.contains(this);
}
/**

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,7 +37,7 @@ public class UDPPort extends IntegerIdentifier
*/
public UDPPort(int value, Role role)
{
super(value, IdentifierClass.NETWORK, Form.UDP_PORT, role);
super(value, IdentifierClass.USER_NETWORK_PORT, Form.UDP_PORT, role);
}
@Override

View File

@@ -76,6 +76,32 @@ public class MPT1327TrafficChannelManager extends TrafficChannelManager implemen
mChannelMap = channelMap;
}
/**
* Notification that the control frequency is updated.
* @param previous frequency for the control channel (to remove from allocated channels)
* @param current frequency for the control channel (to add to allocated channels)
* @param channel for the current control channel
*/
@Override
protected void processControlFrequencyUpdate(long previous, long current, Channel channel)
{
MPT1327Channel toRemove = null;
for(MPT1327Channel mpt: mAllocatedTrafficChannelMap.keySet())
{
if(mpt.getDownlinkFrequency() == current)
{
toRemove = mpt;
break;
}
}
if(toRemove != null)
{
broadcast(new ChannelEvent(mAllocatedTrafficChannelMap.get(toRemove), ChannelEvent.Event.REQUEST_DISABLE));
}
}
/**
* Processes channel grants to allocate traffic channels and track overall channel usage. Generates
* decode events for each new channel that is allocated.

View File

@@ -0,0 +1,16 @@
package io.github.dsheirer.module.decode.p25;
import io.github.dsheirer.module.decode.p25.reference.ServiceOptions;
/**
* APCO25 message that exposes a service options configuration
*/
public interface IServiceOptionsProvider
{
/**
* Service Options
* @return service options
*/
ServiceOptions getServiceOptions();
}

View File

@@ -117,7 +117,7 @@ public class P25ChannelGrantEvent extends P25DecodeEvent
* Sets the channel descriptor for this event
* @param channelDescriptor
*/
public P25ChannelGrantDecodeEventBuilder channel(IChannelDescriptor channelDescriptor)
public P25ChannelGrantDecodeEventBuilder channelDescriptor(IChannelDescriptor channelDescriptor)
{
mChannelDescriptor = channelDescriptor;
return this;

View File

@@ -0,0 +1,22 @@
package io.github.dsheirer.module.decode.p25;
import io.github.dsheirer.controller.channel.event.PreloadDataContent;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
import java.util.Collection;
/**
* Frequency bands (aka Identifier Update) to preload into a traffic channel.
*/
public class P25FrequencyBandPreloadDataContent extends PreloadDataContent<Collection<IFrequencyBand>>
{
/**
* Constructs an instance
*
* @param data to preload
*/
public P25FrequencyBandPreloadDataContent(Collection<IFrequencyBand> data)
{
super(data);
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,14 +23,14 @@ package io.github.dsheirer.module.decode.p25.audio;
import io.github.dsheirer.audio.codec.mbe.MBECallSequence;
import io.github.dsheirer.audio.codec.mbe.MBECallSequenceRecorder;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.module.decode.p25.phase1.message.P25Message;
import io.github.dsheirer.module.decode.p25.phase1.message.P25P1Message;
import io.github.dsheirer.module.decode.p25.phase1.message.hdu.HDUMessage;
import io.github.dsheirer.module.decode.p25.phase1.message.hdu.HeaderData;
import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaPatchGroupVoiceChannelUpdate;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaPatchGroupVoiceChannelUser;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaGroupRegroupVoiceChannelUpdate;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaGroupRegroupVoiceChannelUser;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupVoiceChannelUpdateExplicit;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupVoiceChannelUser;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCTelephoneInterconnectVoiceChannelUser;
@@ -86,9 +86,9 @@ public class P25P1CallSequenceRecorder extends MBECallSequenceRecorder
@Override
public void receive(IMessage message)
{
if(message instanceof P25Message)
if(message instanceof P25P1Message)
{
P25Message p25 = (P25Message)message;
P25P1Message p25 = (P25P1Message)message;
if(p25.isValid())
{
@@ -113,7 +113,7 @@ public class P25P1CallSequenceRecorder extends MBECallSequenceRecorder
/**
* Processes any P25 Phase 1 message
*/
public void process(P25Message message)
public void process(P25P1Message message)
{
if(message instanceof LDUMessage)
{
@@ -200,15 +200,15 @@ public class P25P1CallSequenceRecorder extends MBECallSequenceRecorder
mCallSequence.setToIdentifier(tivcu.getAddress().toString());
mCallSequence.setCallType(CALL_TYPE_TELEPHONE_INTERCONNECT);
break;
case MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_USER:
LCMotorolaPatchGroupVoiceChannelUser mpgvcu = (LCMotorolaPatchGroupVoiceChannelUser)lcw;
case MOTOROLA_GROUP_REGROUP_VOICE_CHANNEL_USER:
LCMotorolaGroupRegroupVoiceChannelUser mpgvcu = (LCMotorolaGroupRegroupVoiceChannelUser)lcw;
mCallSequence.setFromIdentifier(mpgvcu.getSourceAddress().toString());
mCallSequence.setToIdentifier(mpgvcu.getGroupAddress().toString());
mCallSequence.setToIdentifier(mpgvcu.getSupergroupAddress().toString());
mCallSequence.setCallType(CALL_TYPE_GROUP);
break;
case MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_UPDATE:
LCMotorolaPatchGroupVoiceChannelUpdate mpgvcup = (LCMotorolaPatchGroupVoiceChannelUpdate)lcw;
mCallSequence.setToIdentifier(mpgvcup.getPatchGroup().toString());
case MOTOROLA_GROUP_REGROUP_VOICE_CHANNEL_UPDATE:
LCMotorolaGroupRegroupVoiceChannelUpdate mpgvcup = (LCMotorolaGroupRegroupVoiceChannelUpdate)lcw;
mCallSequence.setToIdentifier(mpgvcup.getSupergroupAddress().toString());
mCallSequence.setCallType(CALL_TYPE_GROUP);
break;
case CALL_TERMINATION_OR_CANCELLATION:

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,6 +36,8 @@ import io.github.dsheirer.identifier.tone.ToneSequence;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.message.IMessageProvider;
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.structure.MacStructure;
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.PushToTalk;
import io.github.dsheirer.module.decode.p25.phase2.timeslot.AbstractVoiceTimeslot;
import io.github.dsheirer.preference.UserPreferences;
@@ -111,10 +113,8 @@ public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdat
{
if(message.getTimeslot() == getTimeslot())
{
if(message instanceof AbstractVoiceTimeslot)
if(message instanceof AbstractVoiceTimeslot abstractVoiceTimeslot)
{
AbstractVoiceTimeslot abstractVoiceTimeslot = (AbstractVoiceTimeslot)message;
if(mEncryptedCallStateEstablished)
{
if(!mEncryptedCall)
@@ -128,13 +128,18 @@ public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdat
mQueuedAudioTimeslots.offer(abstractVoiceTimeslot);
}
}
else if(message instanceof PushToTalk && message.isValid())
else if(message instanceof MacMessage macMessage && message.isValid())
{
mEncryptedCallStateEstablished = true;
mEncryptedCall = ((PushToTalk)message).isEncrypted();
MacStructure macStructure = macMessage.getMacStructure();
//There should not be any pending voice timeslots to process since the PTT message is the first in
//the audio call sequence
if(macStructure instanceof PushToTalk pushToTalk)
{
mEncryptedCallStateEstablished = true;
mEncryptedCall = pushToTalk.isEncrypted();
//There should not be any pending voice timeslots to process since the PTT message is the first in
//the audio call sequence.
clearPendingVoiceTimeslots();
}
}
else if(message instanceof EncryptionSynchronizationSequence && message.isValid())
{
@@ -159,6 +164,14 @@ public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdat
}
}
/**
* Clears/deletes any pending voice timeslots
*/
private void clearPendingVoiceTimeslots()
{
mQueuedAudioTimeslots.clear();
}
/**
* Process the audio voice frames
* @param voiceFrames to process

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.audio;
@@ -30,21 +27,20 @@ import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.module.decode.p25.phase2.message.EncryptionSynchronizationSequence;
import io.github.dsheirer.module.decode.p25.phase2.message.P25P2Message;
import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacMessage;
import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure;
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.EndPushToTalk;
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelUserAbbreviated;
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelUserExtended;
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.MacStructure;
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.PushToTalk;
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.TelephoneInterconnectVoiceChannelUser;
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitVoiceChannelUserAbbreviated;
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitVoiceChannelUserExtended;
import io.github.dsheirer.module.decode.p25.phase2.timeslot.AbstractVoiceTimeslot;
import io.github.dsheirer.preference.UserPreferences;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* P25 Phase 2 AMBE Frame recorder generates P25 call sequence recordings containing JSON representations of audio
* frames, optional encryption and call identifiers.
@@ -229,19 +225,19 @@ public class P25P2CallSequenceRecorder extends MBECallSequenceRecorder
case END_PUSH_TO_TALK:
processEndPTT(mac);
break;
case TDMA_1_GROUP_VOICE_CHANNEL_USER_ABBREVIATED:
case TDMA_01_GROUP_VOICE_CHANNEL_USER_ABBREVIATED:
processGVCUA(mac);
break;
case TDMA_2_UNIT_TO_UNIT_VOICE_CHANNEL_USER:
case TDMA_02_UNIT_TO_UNIT_VOICE_CHANNEL_USER_ABBREVIATED:
processUTUVCU(mac);
break;
case TDMA_3_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER:
case TDMA_03_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER:
processTIVCU(mac);
break;
case TDMA_33_GROUP_VOICE_CHANNEL_USER_EXTENDED:
case TDMA_21_GROUP_VOICE_CHANNEL_USER_EXTENDED:
processGVCUE(mac);
break;
case TDMA_34_UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED:
case TDMA_22_UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED:
processUTUVCUE(mac);
break;
}
@@ -258,7 +254,7 @@ public class P25P2CallSequenceRecorder extends MBECallSequenceRecorder
if(mac instanceof UnitToUnitVoiceChannelUserExtended)
{
UnitToUnitVoiceChannelUserExtended uuvcue = (UnitToUnitVoiceChannelUserExtended)mac;
mCallSequence.setFromIdentifier(uuvcue.getSourceAddress().toString());
mCallSequence.setFromIdentifier(uuvcue.getSource().toString());
mCallSequence.setToIdentifier(uuvcue.getTargetAddress().toString());
mCallSequence.setCallType(CALL_TYPE_INDIVIDUAL);
if(uuvcue.getServiceOptions().isEncrypted())
@@ -276,7 +272,7 @@ public class P25P2CallSequenceRecorder extends MBECallSequenceRecorder
if(mac instanceof GroupVoiceChannelUserExtended)
{
GroupVoiceChannelUserExtended gvcue = (GroupVoiceChannelUserExtended)mac;
mCallSequence.setFromIdentifier(gvcue.getSourceAddress().toString());
mCallSequence.setFromIdentifier(gvcue.getSource().toString());
mCallSequence.setToIdentifier(gvcue.getGroupAddress().toString());
mCallSequence.setCallType(CALL_TYPE_GROUP);
if(gvcue.getServiceOptions().isEncrypted())
@@ -294,7 +290,7 @@ public class P25P2CallSequenceRecorder extends MBECallSequenceRecorder
if(mac instanceof TelephoneInterconnectVoiceChannelUser)
{
TelephoneInterconnectVoiceChannelUser tivcu = (TelephoneInterconnectVoiceChannelUser)mac;
mCallSequence.setToIdentifier(tivcu.getToOrFromAddress().toString());
mCallSequence.setToIdentifier(tivcu.getTargetAddress().toString());
mCallSequence.setCallType(CALL_TYPE_TELEPHONE_INTERCONNECT);
if(tivcu.getServiceOptions().isEncrypted())
{

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.identifier;
@@ -46,4 +45,10 @@ public class APCO25Lra extends IntegerIdentifier
{
return new APCO25Lra(lra);
}
@Override
public String toString()
{
return getValue() + "/x" + String.format("%02X", getValue());
}
}

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.identifier;
@@ -52,4 +51,10 @@ public class APCO25Nac extends IntegerIdentifier
{
return new APCO25Nac(nac);
}
@Override
public String toString()
{
return getValue() + "/x" + String.format("%03X", getValue());
}
}

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.identifier;
@@ -46,4 +45,10 @@ public class APCO25Rfss extends IntegerIdentifier
{
return new APCO25Rfss(rfss);
}
@Override
public String toString()
{
return getValue() + "/x" + String.format("%02X", getValue());
}
}

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,12 +14,11 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.identifier;
import io.github.dsheirer.identifier.Form;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.IdentifierClass;
import io.github.dsheirer.identifier.Role;
import io.github.dsheirer.identifier.integer.IntegerIdentifier;
@@ -42,8 +40,14 @@ public class APCO25Site extends IntegerIdentifier
/**
* Creates a new APCO-25 site identifier
*/
public static Identifier create(int site)
public static IntegerIdentifier create(int site)
{
return new APCO25Site(site);
}
@Override
public String toString()
{
return getValue() + "/x" + String.format("%02X", getValue());
}
}

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.identifier;
@@ -45,4 +44,11 @@ public class APCO25System extends IntegerIdentifier
{
return new APCO25System(system);
}
@Override
public String toString()
{
return getValue() + "/x" + String.format("%03X", getValue());
}
}

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.identifier;
@@ -46,4 +45,11 @@ public class APCO25Wacn extends IntegerIdentifier
{
return new APCO25Wacn(wacn);
}
@Override
public String toString()
{
return getValue() + "/x" + String.format("%05X", getValue());
}
}

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.identifier.channel;
@@ -25,7 +22,6 @@ package io.github.dsheirer.module.decode.p25.identifier.channel;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
import io.github.dsheirer.protocol.Protocol;
import java.util.Objects;
public class P25Channel implements IChannelDescriptor
@@ -151,17 +147,24 @@ public class P25Channel implements IChannelDescriptor
}
/**
* Timeslot for a TDMA channel
* @return timeslot or 0 if the channel is not a TDMA channel
* Timeslot for a TDMA channel, 1 or 2
*
* Note: the ICD uses Logical Channel 0 (LCH 0) and Logical Channel 1 (LCH 1) but we refer to them as TS1 and TS2
* so that timeslot 0 can be used for non timeslot signalling like Sync Loss messages.
*
* @return timeslot or 1 if the channel is not a TDMA channel
*/
public int getTimeslot()
{
if(isTDMAChannel())
{
return getDownlinkChannelNumber() % getTimeslotCount();
if(getDownlinkChannelNumber() % getTimeslotCount() == 1)
{
return 2;
}
}
return 0;
return 1;
}
/**

View File

@@ -1,9 +1,27 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.identifier.channel;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
import io.github.dsheirer.protocol.Protocol;
import java.text.DecimalFormat;
/**
@@ -11,7 +29,7 @@ import java.text.DecimalFormat;
*/
public class StandardChannel implements IChannelDescriptor
{
private static final DecimalFormat FREQUENCY_FORMATTER = new DecimalFormat("0.000");
private static final DecimalFormat FREQUENCY_FORMATTER = new DecimalFormat("0.0000");
private long mFrequency;
/**

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,12 +14,13 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.identifier.patch;
import io.github.dsheirer.identifier.patch.PatchGroup;
import io.github.dsheirer.identifier.patch.PatchGroupIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
import io.github.dsheirer.protocol.Protocol;
/**
@@ -43,4 +43,9 @@ public class APCO25PatchGroup extends PatchGroupIdentifier
{
return new APCO25PatchGroup(patchGroup);
}
public static APCO25PatchGroup create(int supergroup)
{
return new APCO25PatchGroup(new PatchGroup(APCO25Talkgroup.create(supergroup)));
}
}

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.identifier.radio;
@@ -31,9 +28,17 @@ import io.github.dsheirer.protocol.Protocol;
*/
public class APCO25FullyQualifiedRadioIdentifier extends FullyQualifiedRadioIdentifier
{
public APCO25FullyQualifiedRadioIdentifier(int wacn, int system, int id, Role role)
/**
* Constructs an instance
* @param localAddress radio identifier. This can be the same as the radio ID when the fully qualified radio
* is not being aliased on a local radio system.
* @param wacn of the home network for the radio.
* @param system of the home network for the radio.
* @param id of the radio within the home network.
*/
public APCO25FullyQualifiedRadioIdentifier(int localAddress, int wacn, int system, int id, Role role)
{
super(wacn, system, id, role);
super(localAddress, wacn, system, id, role);
}
@Override
@@ -42,13 +47,31 @@ public class APCO25FullyQualifiedRadioIdentifier extends FullyQualifiedRadioIden
return Protocol.APCO25;
}
public static APCO25FullyQualifiedRadioIdentifier createFrom(int wacn, int system, int id)
/**
* Creates a fully qualified radio and assigns the FROM role.
* @param localAddress radio identifier. This can be the same as the radio ID when the fully qualified radio
* is not being aliased on a local radio system.
* @param wacn of the home network for the radio.
* @param system of the home network for the radio.
* @param id of the radio within the home network.
* @return identifier
*/
public static APCO25FullyQualifiedRadioIdentifier createFrom(int localAddress, int wacn, int system, int id)
{
return new APCO25FullyQualifiedRadioIdentifier(wacn, system, id, Role.FROM);
return new APCO25FullyQualifiedRadioIdentifier(localAddress, wacn, system, id, Role.FROM);
}
public static APCO25FullyQualifiedRadioIdentifier createTo(int wacn, int system, int id)
/**
* Creates a fully qualified radio and assigns the TO role.
* @param localAddress radio identifier. This can be the same as the radio ID when the fully qualified radio
* is not being aliased on a local radio system.
* @param wacn of the home network for the radio.
* @param system of the home network for the radio.
* @param id of the radio within the home network.
* @return identifier
*/
public static APCO25FullyQualifiedRadioIdentifier createTo(int localAddress, int wacn, int system, int id)
{
return new APCO25FullyQualifiedRadioIdentifier(wacn, system, id, Role.TO);
return new APCO25FullyQualifiedRadioIdentifier(localAddress, wacn, system, id, Role.TO);
}
}

View File

@@ -1,29 +1,30 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.identifier.talkgroup;
import io.github.dsheirer.identifier.Role;
import io.github.dsheirer.identifier.radio.RadioIdentifier;
import io.github.dsheirer.identifier.talkgroup.FullyQualifiedTalkgroupIdentifier;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25FullyQualifiedRadioIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.protocol.Protocol;
/**
@@ -31,9 +32,17 @@ import io.github.dsheirer.protocol.Protocol;
*/
public class APCO25FullyQualifiedTalkgroupIdentifier extends FullyQualifiedTalkgroupIdentifier
{
public APCO25FullyQualifiedTalkgroupIdentifier(int wacn, int system, int id, Role role)
/**
* Constructs an instance
* @param groupAddress used on the local system as an alias to the fully qualified talkgroup.
* @param wacn for the talkgroup home system.
* @param system for the talkgroup home system.
* @param id for the talkgroup within the home system.
* @param role played by the talkgroup.
*/
public APCO25FullyQualifiedTalkgroupIdentifier(int groupAddress, int wacn, int system, int id, Role role)
{
super(wacn, system, id, role);
super(groupAddress, wacn, system, id, role);
}
@Override
@@ -42,18 +51,39 @@ public class APCO25FullyQualifiedTalkgroupIdentifier extends FullyQualifiedTalkg
return Protocol.APCO25;
}
public static APCO25FullyQualifiedTalkgroupIdentifier createFrom(int wacn, int system, int id)
/**
* Creates an identifier for the fully qualified talkgroup ising the FROM role.
* @param groupAddress used on the local system as an alias to the fully qualified talkgroup.
* @param wacn for the talkgroup home system.
* @param system for the talkgroup home system.
* @param id for the talkgroup within the home system.
*/
public static APCO25FullyQualifiedTalkgroupIdentifier createFrom(int groupAddress, int wacn, int system, int id)
{
return new APCO25FullyQualifiedTalkgroupIdentifier(wacn, system, id, Role.FROM);
return new APCO25FullyQualifiedTalkgroupIdentifier(groupAddress, wacn, system, id, Role.FROM);
}
public static APCO25FullyQualifiedTalkgroupIdentifier createTo(int wacn, int system, int id)
/**
* Creates an identifier for the fully qualified talkgroup ising the TO role.
* @param groupAddress used on the local system as an alias to the fully qualified talkgroup.
* @param wacn for the talkgroup home system.
* @param system for the talkgroup home system.
* @param id for the talkgroup within the home system.
*/
public static APCO25FullyQualifiedTalkgroupIdentifier createTo(int groupAddress, int wacn, int system, int id)
{
return new APCO25FullyQualifiedTalkgroupIdentifier(wacn, system, id, Role.TO);
return new APCO25FullyQualifiedTalkgroupIdentifier(groupAddress, wacn, system, id, Role.TO);
}
public static APCO25FullyQualifiedTalkgroupIdentifier createAny(int wacn, int system, int id)
/**
* Creates an identifier for the fully qualified talkgroup ising the ANY role.
* @param groupAddress used on the local system as an alias to the fully qualified talkgroup.
* @param wacn for the talkgroup home system.
* @param system for the talkgroup home system.
* @param id for the talkgroup within the home system.
*/
public static APCO25FullyQualifiedTalkgroupIdentifier createAny(int groupAddress, int wacn, int system, int id)
{
return new APCO25FullyQualifiedTalkgroupIdentifier(wacn, system, id, Role.ANY);
return new APCO25FullyQualifiedTalkgroupIdentifier(groupAddress, wacn, system, id, Role.ANY);
}
}

View File

@@ -0,0 +1,72 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.module.decode.p25.phase2.DecodeConfigP25Phase2;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = DecodeConfigP25Phase1.class, name = "decodeConfigP25Phase1"),
@JsonSubTypes.Type(value = DecodeConfigP25Phase2.class, name = "decodeConfigP25Phase2"),
})
public abstract class DecodeConfigP25 extends DecodeConfiguration
{
private int mTrafficChannelPoolSize = TRAFFIC_CHANNEL_LIMIT_DEFAULT;
private boolean mIgnoreDataCalls = false;
public DecodeConfigP25()
{
}
@JacksonXmlProperty(isAttribute = true, localName = "ignore_data_calls")
public boolean getIgnoreDataCalls()
{
return mIgnoreDataCalls;
}
public void setIgnoreDataCalls(boolean ignore)
{
mIgnoreDataCalls = ignore;
}
@JacksonXmlProperty(isAttribute = true, localName = "traffic_channel_pool_size")
public int getTrafficChannelPoolSize()
{
return mTrafficChannelPoolSize;
}
/**
* Sets the traffic channel pool size which is the maximum number of
* simultaneous traffic channels that can be allocated.
*
* This limits the maximum calls so that busy systems won't cause more
* traffic channels to be allocated than the decoder/software/host computer
* can support.
*/
public void setTrafficChannelPoolSize(int size)
{
mTrafficChannelPoolSize = size;
}
}

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1;
@@ -25,10 +22,12 @@ package io.github.dsheirer.module.decode.p25.phase1;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
public class DecodeConfigP25Phase1 extends DecodeConfiguration
/**
* APCO25 Phase 1 decoder configuration
*/
public class DecodeConfigP25Phase1 extends DecodeConfigP25
{
public static final int CHANNEL_ROTATION_DELAY_MINIMUM_MS = 400;
public static final int CHANNEL_ROTATION_DELAY_DEFAULT_MS = 500;
@@ -36,9 +35,9 @@ public class DecodeConfigP25Phase1 extends DecodeConfiguration
private P25P1Decoder.Modulation mModulation = P25P1Decoder.Modulation.C4FM;
private int mTrafficChannelPoolSize = TRAFFIC_CHANNEL_LIMIT_DEFAULT;
private boolean mIgnoreDataCalls = false;
/**
* Constructs an instance
*/
public DecodeConfigP25Phase1()
{
}
@@ -60,37 +59,6 @@ public class DecodeConfigP25Phase1 extends DecodeConfiguration
mModulation = modulation;
}
@JacksonXmlProperty(isAttribute = true, localName = "ignore_data_calls")
public boolean getIgnoreDataCalls()
{
return mIgnoreDataCalls;
}
public void setIgnoreDataCalls(boolean ignore)
{
mIgnoreDataCalls = ignore;
}
@JacksonXmlProperty(isAttribute = true, localName = "traffic_channel_pool_size")
public int getTrafficChannelPoolSize()
{
return mTrafficChannelPoolSize;
}
/**
* Sets the traffic channel pool size which is the maximum number of
* simultaneous traffic channels that can be allocated.
*
* This limits the maximum calls so that busy systems won't cause more
* traffic channels to be allocated than the decoder/software/host computer
* can support.
*/
public void setTrafficChannelPoolSize(int size)
{
mTrafficChannelPoolSize = size;
}
/**
* Source channel specification for this decoder
*/

View File

@@ -18,11 +18,16 @@
*/
package io.github.dsheirer.module.decode.p25.phase1;
import com.google.common.eventbus.Subscribe;
import io.github.dsheirer.dsp.squelch.PowerMonitor;
import io.github.dsheirer.dsp.symbol.Dibit;
import io.github.dsheirer.dsp.symbol.DibitToByteBufferAssembler;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.Role;
import io.github.dsheirer.identifier.patch.PatchGroupIdentifier;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.FeedbackDecoder;
import io.github.dsheirer.module.decode.p25.P25FrequencyBandPreloadDataContent;
import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.IByteBufferProvider;
@@ -52,6 +57,18 @@ public abstract class P25P1Decoder extends FeedbackDecoder implements ISourceEve
getDibitBroadcaster().addListener(mByteBufferAssembler);
}
/**
* Preloads P25 frequency bands when this is a traffic channel, since they are not transmitted on the traffic
* channel and the decoder state needs accurate frequency values to pass to the traffic channel manager for
* call event tracking.
* @param preLoadDataContent with known frequency bands.
*/
@Subscribe
public void process(P25FrequencyBandPreloadDataContent preLoadDataContent)
{
mMessageProcessor.preload(preLoadDataContent);
}
@Override
public void setSourceEventListener(Listener<SourceEvent> listener )
{

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,7 +30,6 @@ import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop;
import io.github.dsheirer.dsp.symbol.Dibit;
import io.github.dsheirer.dsp.symbol.ISyncDetectListener;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.message.MessageProviderModule;
import io.github.dsheirer.message.StuffBitsMessage;
import io.github.dsheirer.message.SyncLossMessage;
@@ -40,8 +39,8 @@ import io.github.dsheirer.module.decode.ip.ipv4.IPV4Packet;
import io.github.dsheirer.module.decode.ip.mototrbo.lrrp.LRRPPacket;
import io.github.dsheirer.module.decode.ip.udp.UDPPacket;
import io.github.dsheirer.module.decode.p25.audio.P25P1AudioModule;
import io.github.dsheirer.module.decode.p25.phase1.message.P25Message;
import io.github.dsheirer.module.decode.p25.phase1.message.P25MessageFactory;
import io.github.dsheirer.module.decode.p25.phase1.message.P25P1Message;
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUMessageFactory;
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence;
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.PacketMessage;
@@ -73,7 +72,7 @@ public class P25P1MessageFramer implements Listener<Dibit>, IP25P1DataUnitDetect
private P25P1DataUnitDetector mDataUnitDetector;
private P25P1ChannelStatusProcessor mChannelStatusProcessor = new P25P1ChannelStatusProcessor();
private Listener<Message> mMessageListener;
private Listener<IMessage> mMessageListener;
private boolean mAssemblingMessage = false;
private CorrectedBinaryMessage mBinaryMessage;
private P25P1DataUnitID mDataUnitID;
@@ -153,7 +152,7 @@ public class P25P1MessageFramer implements Listener<Dibit>, IP25P1DataUnitDetect
*
* @param messageListener to receive framed and decoded messages
*/
public void setListener(Listener<Message> messageListener)
public void setListener(Listener<IMessage> messageListener)
{
mMessageListener = messageListener;
}
@@ -346,7 +345,7 @@ public class P25P1MessageFramer implements Listener<Dibit>, IP25P1DataUnitDetect
}
break;
default:
P25Message message = P25MessageFactory.create(mDataUnitID, mNAC, getTimestamp(), mBinaryMessage);
P25P1Message message = P25MessageFactory.create(mDataUnitID, mNAC, getTimestamp(), mBinaryMessage);
mMessageListener.receive(message);
reset(mDataUnitID.getMessageLength());
break;

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,44 +20,81 @@ package io.github.dsheirer.module.decode.p25.phase1;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.module.decode.p25.P25FrequencyBandPreloadDataContent;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.ExtendedSourceLinkControlWord;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCSourceIDExtension;
import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU1Message;
import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDULinkControlMessage;
import io.github.dsheirer.sample.Listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class P25P1MessageProcessor implements Listener<Message>
/**
* APCO25 Phase 1 Message Processor.
*
* Performs post-message creation processing before the message is sent downstream.
*/
public class P25P1MessageProcessor implements Listener<IMessage>
{
private final static Logger mLog = LoggerFactory.getLogger(P25P1MessageProcessor.class);
/**
* Downstream message listener
*/
private Listener<IMessage> mMessageListener;
/* Map of up to 16 band identifiers per RFSS. These identifier update
* messages are inserted into any message that conveys channel information
* so that the uplink/downlink frequencies can be calculated */
/**
* Map of up to 16 band identifiers per RFSS. These identifier update messages are inserted into any message that
* conveys channel information so that the uplink/downlink frequencies can be calculated
*/
private Map<Integer,IFrequencyBand> mFrequencyBandMap = new TreeMap<Integer,IFrequencyBand>();
/**
* Temporary holding of an extended source link control message while it awaits the extension message to arrive.
*/
private ExtendedSourceLinkControlWord mExtendedSourceLinkControlWord;
public P25P1MessageProcessor()
{
}
@Override
public void receive(Message message)
/**
* Preloads frequency band information from the control channel.
* @param content to preload
*/
public void preload(P25FrequencyBandPreloadDataContent content)
{
if(content.hasData())
{
for(IFrequencyBand frequencyBand: content.getData())
{
mFrequencyBandMap.put(frequencyBand.getIdentifier(), frequencyBand);
}
}
}
@Override
public void receive(IMessage message)
{
/**
* Capture frequency band identifier messages and inject them into any
* messages that require band information in order to calculate the
* up-link and down-link frequencies for any numeric channel references
* contained within the message.
*/
if(message.isValid())
{
/* Insert frequency band identifier update messages into channel-type messages */
//Reassemble extended source link control messages.
if(message instanceof LDU1Message ldu)
{
reassembleLC(ldu.getLinkControlWord());
}
else if(message instanceof TDULinkControlMessage tdu)
{
reassembleLC(tdu.getLinkControlWord());
}
//Insert frequency band identifier update messages into channel-type messages */
if(message instanceof IFrequencyBandReceiver)
{
IFrequencyBandReceiver receiver = (IFrequencyBandReceiver)message;
@@ -78,8 +115,7 @@ public class P25P1MessageProcessor implements Listener<Message>
}
}
/* Store band identifiers so that they can be injected into channel
* type messages */
//Store band identifiers so that they can be injected into channel type messages
if(message instanceof IFrequencyBand)
{
IFrequencyBand bandIdentifier = (IFrequencyBand)message;
@@ -93,6 +129,30 @@ public class P25P1MessageProcessor implements Listener<Message>
}
}
/**
* Processes link control words to reassemble source ID extension messages.
* @param linkControlWord to process
*/
private void reassembleLC(LinkControlWord linkControlWord)
{
if(linkControlWord instanceof ExtendedSourceLinkControlWord eslcw)
{
mExtendedSourceLinkControlWord = eslcw;
}
else if(linkControlWord instanceof LCSourceIDExtension sie && mExtendedSourceLinkControlWord != null)
{
mExtendedSourceLinkControlWord.setSourceIDExtension(sie);
mExtendedSourceLinkControlWord = null;
}
else
{
//The source extension message should always immediately follow the message that is being extended, so if
//we get a message that is not an extended message or the extension, then we've missed the extension and we
//should nullify any extended message that's waiting for the extension.
mExtendedSourceLinkControlWord = null;
}
}
public void dispose()
{
mFrequencyBandMap.clear();

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,16 +45,15 @@ import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SND
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SecondaryControlChannelBroadcast;
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SecondaryControlChannelBroadcastExplicit;
import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SystemServiceBroadcast;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Tracks the network configuration details of a P25 Phase 1 network from the broadcast messages
@@ -236,7 +235,7 @@ public class P25P1NetworkConfigurationMonitor
}
break;
case CHANNEL_IDENTIFIER_UPDATE:
case CHANNEL_IDENTIFIER_UPDATE_EXPLICIT:
case CHANNEL_IDENTIFIER_UPDATE_VU:
if(lcw instanceof IFrequencyBand)
{
IFrequencyBand band = (IFrequencyBand)lcw;

View File

@@ -0,0 +1,95 @@
package io.github.dsheirer.module.decode.p25.phase1.message;
import org.apache.commons.math3.util.FastMath;
/**
* Utility class to declare a frequency band
*/
public class P25FrequencyBand implements IFrequencyBand
{
private int mIdentifier;
private long mBaseFrequency;
private long mTransmitOffset;
private long mChannelSpacing;
private int mBandwidth;
private int mTimeslotCount;
/**
* Construct an instance
* @param identifier for this frequency band
* @param baseFrequency in Hertz
* @param transmitOffset in Hertz
* @param channelSpacing in Hertz
* @param bandwidth in Hertz
* @param timeslotCount for number of timeslots, 1 or 2
*/
public P25FrequencyBand(int identifier, long baseFrequency, long transmitOffset, long channelSpacing,
int bandwidth, int timeslotCount)
{
mIdentifier = identifier;
mChannelSpacing = channelSpacing;
mBaseFrequency = baseFrequency;
mBandwidth = bandwidth;
mTransmitOffset = transmitOffset;
mTimeslotCount = timeslotCount;
}
@Override
public int getIdentifier()
{
return mIdentifier;
}
@Override
public long getChannelSpacing()
{
return mChannelSpacing;
}
@Override
public long getBaseFrequency()
{
return mBaseFrequency;
}
@Override
public int getBandwidth()
{
return mBandwidth;
}
@Override
public long getTransmitOffset()
{
return mTransmitOffset;
}
@Override
public long getDownlinkFrequency(int channelNumber)
{
if(isTDMA())
{
return getBaseFrequency() + (getChannelSpacing() * (int)(FastMath.floor(channelNumber / getTimeslotCount())));
}
return getBaseFrequency() + (getChannelSpacing() * channelNumber);
}
@Override
public long getUplinkFrequency(int channelNumber)
{
return getDownlinkFrequency(channelNumber) + getTransmitOffset();
}
@Override
public boolean isTDMA()
{
return getTimeslotCount() > 1;
}
@Override
public int getTimeslotCount()
{
return mTimeslotCount;
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -49,7 +49,7 @@ public class P25MessageFactory
* correction
* @return constructed message parser
*/
public static P25Message create(P25P1DataUnitID dataUnitID, int nac, long timestamp, CorrectedBinaryMessage message)
public static P25P1Message create(P25P1DataUnitID dataUnitID, int nac, long timestamp, CorrectedBinaryMessage message)
{
switch(dataUnitID)
{

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,25 +20,32 @@ package io.github.dsheirer.module.decode.p25.phase1.message;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.message.TimeslotMessage;
import io.github.dsheirer.module.decode.p25.identifier.APCO25Nac;
import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID;
import io.github.dsheirer.protocol.Protocol;
public abstract class P25Message extends Message
/**
* Base APCO25 Phase 1 Message
*/
public abstract class P25P1Message extends TimeslotMessage implements IMessage
{
public enum DuplexMode
{
HALF, FULL
}
//P25 Phase 1 ICD defines octets starting at zero.
public static final int OCTET_0_BIT_0 = 0;
public static final int OCTET_1_BIT_8 = 8;
public static final int OCTET_2_BIT_16 = 16;
public static final int OCTET_3_BIT_24 = 24;
public static final int OCTET_4_BIT_32 = 32;
public static final int OCTET_5_BIT_40 = 40;
public static final int OCTET_6_BIT_48 = 48;
public static final int OCTET_7_BIT_56 = 56;
public static final int OCTET_8_BIT_64 = 64;
public static final int OCTET_9_BIT_72 = 72;
public static final int OCTET_10_BIT_80 = 80;
public static final int OCTET_11_BIT_88 = 88;
public static final int OCTET_12_BIT_96 = 96;
public enum SessionMode
{
PACKET, CIRCUIT
}
private CorrectedBinaryMessage mMessage;
private boolean mValid = true;
private Identifier mNAC;
/**
@@ -48,10 +55,9 @@ public abstract class P25Message extends Message
* @param nac Network Access Code (NAC) for the message
* @param timestamp when the message was transmitted
*/
public P25Message(CorrectedBinaryMessage message, int nac, long timestamp)
public P25P1Message(CorrectedBinaryMessage message, int nac, long timestamp)
{
super(timestamp);
mMessage = message;
super(message, 0, timestamp);
mNAC = APCO25Nac.create(nac);
}
@@ -61,7 +67,7 @@ public abstract class P25Message extends Message
* @param message containing the binary message and optional corrected bit count
* @param nac Network Access Code (NAC) for the message
*/
public P25Message(CorrectedBinaryMessage message, int nac)
public P25P1Message(CorrectedBinaryMessage message, int nac)
{
this(message, nac, System.currentTimeMillis());
}
@@ -71,28 +77,15 @@ public abstract class P25Message extends Message
* @param nac Network Access Code (NAC) for the message
* @param timestamp when the message was transmitted
*/
protected P25Message(int nac, long timestamp)
protected P25P1Message(int nac, long timestamp)
{
super(timestamp);
super(null, 0, timestamp);
mNAC = APCO25Nac.create(nac);
}
/**
* Establishes the message binary sequence.
* NAC code for this message
*/
protected void setMessage(CorrectedBinaryMessage message)
{
mMessage = message;
}
/**
* The transmitted binary message
*/
public CorrectedBinaryMessage getMessage()
{
return mMessage;
}
public Identifier getNAC()
{
return mNAC;
@@ -125,21 +118,4 @@ public abstract class P25Message extends Message
{
return Protocol.APCO25;
}
/**
* Indicates if this message is valid and has passed all error detection and correction routines.
*/
@Override
public boolean isValid()
{
return mValid;
}
/**
* Sets this message to the valid/invalid state. The default state is valid (true).
*/
protected void setValid(boolean valid)
{
mValid = valid;
}
}

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message;
@@ -23,20 +22,19 @@ package io.github.dsheirer.module.decode.p25.phase1.message;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID;
import java.util.Collections;
import java.util.List;
/**
* P25 Message with unknown or unrecognized data unit id
*/
public class UnknownP25Message extends P25Message
public class UnknownP25Message extends P25P1Message
{
private P25P1DataUnitID mDataUnitID;
public UnknownP25Message(CorrectedBinaryMessage message, int nac, long timestamp, P25P1DataUnitID dataUnitID)
{
super(message, nac);
super(message, nac, timestamp);
mDataUnitID = dataUnitID;
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@ package io.github.dsheirer.module.decode.p25.phase1.message.filter;
import io.github.dsheirer.filter.Filter;
import io.github.dsheirer.filter.FilterElement;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.module.decode.p25.phase1.message.P25Message;
import io.github.dsheirer.module.decode.p25.phase1.message.P25P1Message;
import java.util.function.Function;
/**
@@ -51,7 +51,7 @@ public class P25OtherMessageFilter extends Filter<IMessage,String>
@Override
public boolean canProcess(IMessage message)
{
return message instanceof P25Message && super.canProcess(message);
return message instanceof P25P1Message && super.canProcess(message);
}
/**
@@ -62,7 +62,7 @@ public class P25OtherMessageFilter extends Filter<IMessage,String>
@Override
public String apply(IMessage message)
{
if(message instanceof P25Message)
if(message instanceof P25P1Message)
{
return OTHER_KEY;
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,7 +23,7 @@ import io.github.dsheirer.filter.FilterSet;
import io.github.dsheirer.filter.SyncLossMessageFilter;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.message.SyncLossMessage;
import io.github.dsheirer.module.decode.p25.phase1.message.P25Message;
import io.github.dsheirer.module.decode.p25.phase1.message.P25P1Message;
/**
* Filter set for P25 messages
@@ -53,6 +53,6 @@ public class P25P1MessageFilterSet extends FilterSet<IMessage>
@Override
public boolean canProcess(IMessage message)
{
return message instanceof P25Message || message instanceof SyncLossMessage;
return message instanceof P25P1Message || message instanceof SyncLossMessage;
}
}

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.hdu;
@@ -27,20 +24,19 @@ import io.github.dsheirer.edac.Golay18;
import io.github.dsheirer.edac.ReedSolomon_63_47_17_P25;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID;
import io.github.dsheirer.module.decode.p25.phase1.message.P25Message;
import io.github.dsheirer.module.decode.p25.phase1.message.P25P1Message;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
public class HDUMessage extends P25Message
public class HDUMessage extends P25P1Message
{
private final static Logger mLog = LoggerFactory.getLogger(HDUMessage.class);
private static final int[] GOLAY_WORD_STARTS = {0, 18, 36, 54, 72, 90, 108, 126, 144, 162, 180, 198, 216, 234, 252,
270, 288, 306, 324, 342, 360, 278, 396, 414, 432, 450, 468, 486, 504, 522, 540, 558, 576, 594, 612, 630};
private static final int[] CW_HEX_0 = {0, 1, 2, 3, 4, 5, 6};
private static final int[] CW_HEX_0 = {0, 1, 2, 3, 4, 5};
private static final int[] CW_HEX_1 = {18, 19, 20, 21, 22, 23};
private static final int[] CW_HEX_2 = {36, 37, 38, 39, 40, 41};
private static final int[] CW_HEX_3 = {54, 55, 56, 57, 58, 59};

View File

@@ -0,0 +1,88 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.radio.FullyQualifiedRadioIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25FullyQualifiedRadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCSourceIDExtension;
/**
* Extended link control word. Base class for adding in the extension word for messages that require two link control
* fragments to fit the content.
*/
public abstract class ExtendedSourceLinkControlWord extends LinkControlWord
{
private static final IntField SOURCE_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private LCSourceIDExtension mSourceIDExtension;
private FullyQualifiedRadioIdentifier mSourceAddress;
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public ExtendedSourceLinkControlWord(CorrectedBinaryMessage message)
{
super(message);
}
/**
* Optional source ID extension message for a fully qualified radio source.
*/
protected LCSourceIDExtension getSourceIDExtension()
{
return mSourceIDExtension;
}
/**
* Sets the extension message.
*/
public void setSourceIDExtension(LCSourceIDExtension extension)
{
mSourceIDExtension = extension;
}
/**
* Indicates if this message is carrying a source ID extension message.
*/
protected boolean hasSourceIDExtension()
{
return mSourceIDExtension != null;
}
/**
* Source address
*/
public FullyQualifiedRadioIdentifier getSourceAddress()
{
if(mSourceAddress == null && hasSourceIDExtension())
{
int radio = getInt(SOURCE_ADDRESS);
int wacn = getSourceIDExtension().getWACN();
int system = getSourceIDExtension().getSystem();
int id = getSourceIDExtension().getId();
mSourceAddress = APCO25FullyQualifiedRadioIdentifier.createFrom(radio, wacn, system, id);
}
return mSourceAddress;
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,8 +36,8 @@ public enum LinkControlOpcode
TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER("TELEPHONE INTERCONNECT VOICE CHANNEL USER", 6),
TELEPHONE_INTERCONNECT_ANSWER_REQUEST("TELEPHONE INTERCONNECT ANSWER REQUEST", 7),
RESERVED_08("RESERVED-08", 8),
RESERVED_09("RESERVED-09", 9),
RESERVED_0A("RESERVED-0A", 10),
SOURCE_ID_EXTENSION("SOURCE ID EXTENSION", 9),
UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED("UNIT-TO-UNIT VOICE CHANNEL USER EXTENDED", 10),
RESERVED_0B("RESERVED-0B", 11),
RESERVED_0C("RESERVED-0C", 12),
RESERVED_0D("RESERVED-0D", 13),
@@ -52,10 +52,10 @@ public enum LinkControlOpcode
CALL_ALERT("CALL ALERT", 22),
EXTENDED_FUNCTION_COMMAND("EXTENDED FUNCTION COMMAND", 23),
CHANNEL_IDENTIFIER_UPDATE("CHANNEL IDENTIFIER UPDATE", 24),
CHANNEL_IDENTIFIER_UPDATE_EXPLICIT("CHANNEL IDENTIFIER UPDATE EXPLICIT", 25),
RESERVED_1A("RESERVED-1A", 26),
RESERVED_1B("RESERVED-1B", 27),
RESERVED_1C("RESERVED-1C", 28),
CHANNEL_IDENTIFIER_UPDATE_VU("CHANNEL IDENTIFIER UPDATE EXPLICIT", 25),
STATUS_UPDATE_EXTENDED("STATUS UPDATE-SOURCE ID REQUIRED", 26),
MESSAGE_UPDATE_EXTENDED("MESSAGE UPDATE-SOURCE ID REQUIRED", 27),
EXTENDED_FUNCTION_COMMAND_EXTENDED("EXTENDED FUNCTION COMMAND-SOURCE ID REQUIRED", 28),
RESERVED_1D("RESERVED-1D", 29),
RESERVED_1E("RESERVED-1E", 30),
RESERVED_1F("RESERVED-1F", 31),
@@ -69,7 +69,7 @@ public enum LinkControlOpcode
ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT("ADJACENT SITE STATUS EXPLICIT", 39),
RFSS_STATUS_BROADCAST_EXPLICIT("RFSS STATUS BROADCAST EXPLICIT", 40),
NETWORK_STATUS_BROADCAST_EXPLICIT("NETWORK STATUS BROADCAST EXPLICIT", 41),
RESERVED_2A("RESERVED-2A", 42),
CONVENTIONAL_FALLBACK_INDICATION("CONVENTIONAL FALLBACK INDICATION", 42),
RESERVED_2B("RESERVED-2B", 43),
RESERVED_2C("RESERVED-2C", 44),
RESERVED_2D("RESERVED-2D", 45),
@@ -92,15 +92,18 @@ public enum LinkControlOpcode
RESERVED_3E("RESERVED-3E", 62),
RESERVED_3F("RESERVED-3F", 63),
MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_USER("PATCH GROUP VOICE CHANNEL USER", 0),
MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_UPDATE("PATCH GROUP VOICE CHANNEL UPDATE", 1),
MOTOROLA_PATCH_GROUP_ADD("PATCH GROUP ADD", 3),
MOTOROLA_PATCH_GROUP_DELETE("PATCH GROUP DELETE", 4),
MOTOROLA_UNIT_GPS("UNIT GPS", 6),
MOTOROLA_TALK_COMPLETE("TALK_COMPLETE", 15),
MOTOROLA_GROUP_REGROUP_VOICE_CHANNEL_USER("MOTOROLA GROUP REGROUP VOICE CHANNEL USER", 0),
MOTOROLA_GROUP_REGROUP_VOICE_CHANNEL_UPDATE("MOTOROLA GROUP REGROUP VOICE CHANNEL UPDATE", 1),
MOTOROLA_GROUP_REGROUP_ADD("MOTOROLA GROUP REGROUP ADD", 3),
MOTOROLA_GROUP_REGROUP_DELETE("MOTOROLA GROUP REGROUP DELETE", 4),
MOTOROLA_UNIT_GPS("MOTOROLA UNIT GPS", 6),
MOTOROLA_EMERGENCY_ALARM_ACTIVATION("MOTOROLA EMERGENCY ALARM ACTIVATION", 10),
MOTOROLA_TALK_COMPLETE("MOTOROLA TALK_COMPLETE", 15),
MOTOROLA_RADIO_REPROGRAM_HEADER("MOTOROLA RADIO REPROGRAM HEADER", 21),
MOTOROLA_RADIO_REPROGRAM_RECORD("MOTOROLA RADIO REPROGRAM CONTINUATION", 23),
MOTOROLA_UNKNOWN("MOTOROLA UNKNOWN", -1),
L3HARRIS_UNKNOWN_0A("UNKNOWN OPCODE 10", 10),
L3HARRIS_RETURN_TO_CONTROL_CHANNEL("UNKNOWN OPCODE 10", 10),
L3HARRIS_UNKNOWN_2A("UNKNOWN OPCODE 42", 42),
L3HARRIS_UNKNOWN_2B("UNKNOWN OPCODE 43", 43),
L3HARRIS_UNKNOWN("L3HARRIS UNKNOWN", -1),
@@ -133,19 +136,19 @@ public enum LinkControlOpcode
* Motorola Opcodes
*/
public static final EnumSet<LinkControlOpcode> MOTOROLA_OPCODES =
EnumSet.range(MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_USER, MOTOROLA_UNKNOWN);
EnumSet.range(MOTOROLA_GROUP_REGROUP_VOICE_CHANNEL_USER, MOTOROLA_UNKNOWN);
/**
* L3Harris Opcodes
*/
public static final EnumSet<LinkControlOpcode> L3HARRIS_OPCODES = EnumSet.of(L3HARRIS_UNKNOWN_0A,
public static final EnumSet<LinkControlOpcode> L3HARRIS_OPCODES = EnumSet.of(L3HARRIS_RETURN_TO_CONTROL_CHANNEL,
L3HARRIS_UNKNOWN_2A, L3HARRIS_UNKNOWN_2B, L3HARRIS_UNKNOWN);
/**
* Network/channel related opcodes
*/
public static final EnumSet<LinkControlOpcode> NETWORK_OPCODES = EnumSet.of(CHANNEL_IDENTIFIER_UPDATE,
CHANNEL_IDENTIFIER_UPDATE_EXPLICIT, SYSTEM_SERVICE_BROADCAST, SECONDARY_CONTROL_CHANNEL_BROADCAST,
CHANNEL_IDENTIFIER_UPDATE_VU, SYSTEM_SERVICE_BROADCAST, SECONDARY_CONTROL_CHANNEL_BROADCAST,
SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT, ADJACENT_SITE_STATUS_BROADCAST,
ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT, RFSS_STATUS_BROADCAST, RFSS_STATUS_BROADCAST_EXPLICIT,
NETWORK_STATUS_BROADCAST, NETWORK_STATUS_BROADCAST_EXPLICIT, PROTECTION_PARAMETER_BROADCAST);
@@ -205,7 +208,7 @@ public enum LinkControlOpcode
switch(value)
{
case 10:
return L3HARRIS_UNKNOWN_0A;
return L3HARRIS_RETURN_TO_CONTROL_CHANNEL;
case 42:
return L3HARRIS_UNKNOWN_2A;
case 43:
@@ -217,17 +220,23 @@ public enum LinkControlOpcode
switch(value)
{
case 0:
return MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_USER;
return MOTOROLA_GROUP_REGROUP_VOICE_CHANNEL_USER;
case 1:
return MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_UPDATE;
return MOTOROLA_GROUP_REGROUP_VOICE_CHANNEL_UPDATE;
case 3:
return MOTOROLA_PATCH_GROUP_ADD;
return MOTOROLA_GROUP_REGROUP_ADD;
case 4:
return MOTOROLA_PATCH_GROUP_DELETE;
return MOTOROLA_GROUP_REGROUP_DELETE;
case 6:
return MOTOROLA_UNIT_GPS;
case 10:
return MOTOROLA_EMERGENCY_ALARM_ACTIVATION;
case 15:
return MOTOROLA_TALK_COMPLETE;
case 21:
return MOTOROLA_RADIO_REPROGRAM_HEADER;
case 23:
return MOTOROLA_RADIO_REPROGRAM_RECORD;
default:
return MOTOROLA_UNKNOWN;
}

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,66 +14,73 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.FragmentedIntField;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.message.AbstractMessage;
import io.github.dsheirer.module.decode.p25.reference.Vendor;
import java.util.List;
/**
* APCO 25 Link Control Word. This message word is contained in Logical Link Data Unit 1 and Terminator with
* Link Control messages.
*/
public abstract class LinkControlWord
public abstract class LinkControlWord extends AbstractMessage
{
public static final int OCTET_0_BIT_0 = 0;
public static final int OCTET_1_BIT_8 = 8;
public static final int OCTET_2_BIT_16 = 16;
public static final int OCTET_3_BIT_24 = 24;
public static final int OCTET_4_BIT_32 = 32;
public static final int OCTET_5_BIT_40 = 40;
public static final int OCTET_6_BIT_48 = 48;
public static final int OCTET_7_BIT_56 = 56;
public static final int OCTET_8_BIT_64 = 64;
public static final int OCTET_9_BIT_72 = 72;
public static final int OCTET_10_BIT_80 = 80;
public static final int OCTET_11_BIT_88 = 88;
public static final int OCTET_12_BIT_96 = 96;
private static final int ENCRYPTION_FLAG = 0;
private static final int STANDARD_VENDOR_ID_FLAG = 1;
private static final int[] OPCODE = {2, 3, 4, 5, 6, 7};
private static final int[] VENDOR = {8, 9, 10, 11, 12, 13, 14, 15};
private BinaryMessage mMessage;
private static final FragmentedIntField OPCODE = FragmentedIntField.of(2, 3, 4, 5, 6, 7);
private static final IntField VENDOR = IntField.length8(OCTET_1_BIT_8);
private LinkControlOpcode mLinkControlOpcode;
private boolean mValid = true;
private boolean mValid;
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LinkControlWord(BinaryMessage message)
public LinkControlWord(CorrectedBinaryMessage message)
{
mMessage = message;
super(message);
}
/**
* Binary message sequence for this LCW
*/
protected BinaryMessage getMessage()
{
return mMessage;
}
/**
* Sets the valid flag for this message to mark a flag as invalid (false) or the default value is true.
*/
public void setValid(boolean valid)
{
mValid = valid;
}
/**
* Indicates if this link control word is valid and has passed all error detection and correction routines.
* Indicates if the message passes CRC checks.
*/
public boolean isValid()
{
return mValid;
}
/**
* Sets the valid flag for this message.
*/
public void setValid(boolean valid)
{
mValid = valid;
}
/**
* Indicates if this is an encrypted LCW
*/
@@ -110,7 +116,7 @@ public abstract class LinkControlWord
/**
* Lookup the Vendor format for the specified LCW
*/
public static Vendor getVendor(BinaryMessage binaryMessage)
public static Vendor getVendor(CorrectedBinaryMessage binaryMessage)
{
if(isStandardVendorFormat(binaryMessage))
{
@@ -140,13 +146,13 @@ public abstract class LinkControlWord
*/
public int getOpcodeNumber()
{
return getMessage().getInt(OPCODE);
return getInt(OPCODE);
}
/**
* Identifies the link control word opcode from the binary message.
*/
public static LinkControlOpcode getOpcode(BinaryMessage binaryMessage)
public static LinkControlOpcode getOpcode(CorrectedBinaryMessage binaryMessage)
{
return LinkControlOpcode.fromValue(binaryMessage.getInt(OPCODE), getVendor(binaryMessage));
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,14 +19,17 @@
package io.github.dsheirer.module.decode.p25.phase1.message.lc;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.l3harris.LCHarrisUnknownOpcode10;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.l3harris.LCHarrisReturnToControlChannel;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.l3harris.LCHarrisUnknownOpcode42;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.l3harris.LCHarrisUnknownOpcode43;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaPatchGroupAdd;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaPatchGroupDelete;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaPatchGroupVoiceChannelUpdate;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaPatchGroupVoiceChannelUser;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaEmergencyAlarmActivation;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaGroupGroupDelete;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaGroupRegroupAdd;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaGroupRegroupVoiceChannelUpdate;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaGroupRegroupVoiceChannelUser;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaRadioReprogramHeader;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaRadioReprogramRecord;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaTalkComplete;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaUnitGPS;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaUnknownOpcode;
@@ -34,14 +37,17 @@ import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCAdjacen
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCAdjacentSiteStatusBroadcastExplicit;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCCallAlert;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCCallTermination;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCChannelIdentifierUpdate;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCChannelIdentifierUpdateVU;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCConventionalFallback;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCExtendedFunctionCommand;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCFrequencyBandUpdate;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCFrequencyBandUpdateExplicit;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCExtendedFunctionCommandExtended;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupAffiliationQuery;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupVoiceChannelUpdate;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupVoiceChannelUpdateExplicit;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCGroupVoiceChannelUser;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCMessageUpdate;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCMessageUpdateExtended;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCNetworkStatusBroadcast;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCNetworkStatusBroadcastExplicit;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCProtectionParameterBroadcast;
@@ -49,8 +55,10 @@ import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCRFSSSta
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCRFSSStatusBroadcastExplicit;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCSecondaryControlChannelBroadcast;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCSecondaryControlChannelBroadcastExplicit;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCSourceIDExtension;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCStatusQuery;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCStatusUpdate;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCStatusUpdateExtended;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCSystemServiceBroadcast;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCTelephoneInterconnectAnswerRequest;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCTelephoneInterconnectVoiceChannelUser;
@@ -58,6 +66,7 @@ import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCUnitAut
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCUnitRegistrationCommand;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCUnitToUnitAnswerRequest;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCUnitToUnitVoiceChannelUser;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCUnitToUnitVoiceChannelUserExtended;
/**
* Factory class for creating link control word (LCW) message parsers.
@@ -67,96 +76,114 @@ public class LinkControlWordFactory
/**
* Creates a link control word from the binary message sequence.
*
* @param binaryMessage containing the LCW binary message sequence.
* @param message containing the LCW binary message sequence.
*/
public static LinkControlWord create(BinaryMessage binaryMessage)
public static LinkControlWord create(CorrectedBinaryMessage message)
{
LinkControlOpcode opcode = LinkControlWord.getOpcode(binaryMessage);
LinkControlOpcode opcode = LinkControlWord.getOpcode(message);
switch(opcode)
{
case ADJACENT_SITE_STATUS_BROADCAST:
return new LCAdjacentSiteStatusBroadcast(binaryMessage);
return new LCAdjacentSiteStatusBroadcast(message);
case ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT:
return new LCAdjacentSiteStatusBroadcastExplicit(binaryMessage);
return new LCAdjacentSiteStatusBroadcastExplicit(message);
case CALL_ALERT:
return new LCCallAlert(binaryMessage);
return new LCCallAlert(message);
case CALL_TERMINATION_OR_CANCELLATION:
return new LCCallTermination(binaryMessage);
return new LCCallTermination(message);
case CHANNEL_IDENTIFIER_UPDATE:
return new LCFrequencyBandUpdate(binaryMessage);
case CHANNEL_IDENTIFIER_UPDATE_EXPLICIT:
return new LCFrequencyBandUpdateExplicit(binaryMessage);
return new LCChannelIdentifierUpdate(message);
case CHANNEL_IDENTIFIER_UPDATE_VU:
return new LCChannelIdentifierUpdateVU(message);
case CONVENTIONAL_FALLBACK_INDICATION:
return new LCConventionalFallback(message);
case EXTENDED_FUNCTION_COMMAND:
return new LCExtendedFunctionCommand(binaryMessage);
return new LCExtendedFunctionCommand(message);
case EXTENDED_FUNCTION_COMMAND_EXTENDED:
return new LCExtendedFunctionCommandExtended(message);
case GROUP_AFFILIATION_QUERY:
return new LCGroupAffiliationQuery(binaryMessage);
return new LCGroupAffiliationQuery(message);
case GROUP_VOICE_CHANNEL_USER:
return new LCGroupVoiceChannelUser(binaryMessage);
return new LCGroupVoiceChannelUser(message);
case GROUP_VOICE_CHANNEL_UPDATE:
return new LCGroupVoiceChannelUpdate(binaryMessage);
return new LCGroupVoiceChannelUpdate(message);
case GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT:
return new LCGroupVoiceChannelUpdateExplicit(binaryMessage);
return new LCGroupVoiceChannelUpdateExplicit(message);
case MESSAGE_UPDATE:
return new LCMessageUpdate(binaryMessage);
return new LCMessageUpdate(message);
case MESSAGE_UPDATE_EXTENDED:
return new LCMessageUpdateExtended(message);
case NETWORK_STATUS_BROADCAST:
return new LCNetworkStatusBroadcast(binaryMessage);
return new LCNetworkStatusBroadcast(message);
case NETWORK_STATUS_BROADCAST_EXPLICIT:
return new LCNetworkStatusBroadcastExplicit(binaryMessage);
return new LCNetworkStatusBroadcastExplicit(message);
case PROTECTION_PARAMETER_BROADCAST:
return new LCProtectionParameterBroadcast(binaryMessage);
return new LCProtectionParameterBroadcast(message);
case RFSS_STATUS_BROADCAST:
return new LCRFSSStatusBroadcast(binaryMessage);
return new LCRFSSStatusBroadcast(message);
case RFSS_STATUS_BROADCAST_EXPLICIT:
return new LCRFSSStatusBroadcastExplicit(binaryMessage);
return new LCRFSSStatusBroadcastExplicit(message);
case SECONDARY_CONTROL_CHANNEL_BROADCAST:
return new LCSecondaryControlChannelBroadcast(binaryMessage);
return new LCSecondaryControlChannelBroadcast(message);
case SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT:
return new LCSecondaryControlChannelBroadcastExplicit(binaryMessage);
return new LCSecondaryControlChannelBroadcastExplicit(message);
case SOURCE_ID_EXTENSION:
return new LCSourceIDExtension(message);
case STATUS_QUERY:
return new LCStatusQuery(binaryMessage);
return new LCStatusQuery(message);
case STATUS_UPDATE:
return new LCStatusUpdate(binaryMessage);
return new LCStatusUpdate(message);
case STATUS_UPDATE_EXTENDED:
return new LCStatusUpdateExtended(message);
case SYSTEM_SERVICE_BROADCAST:
return new LCSystemServiceBroadcast(binaryMessage);
return new LCSystemServiceBroadcast(message);
case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
return new LCTelephoneInterconnectAnswerRequest(binaryMessage);
return new LCTelephoneInterconnectAnswerRequest(message);
case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER:
return new LCTelephoneInterconnectVoiceChannelUser(binaryMessage);
return new LCTelephoneInterconnectVoiceChannelUser(message);
case UNIT_AUTHENTICATION_COMMAND:
return new LCUnitAuthenticationCommand(binaryMessage);
return new LCUnitAuthenticationCommand(message);
case UNIT_REGISTRATION_COMMAND:
return new LCUnitRegistrationCommand(binaryMessage);
return new LCUnitRegistrationCommand(message);
case UNIT_TO_UNIT_ANSWER_REQUEST:
return new LCUnitToUnitAnswerRequest(binaryMessage);
return new LCUnitToUnitAnswerRequest(message);
case UNIT_TO_UNIT_VOICE_CHANNEL_USER:
return new LCUnitToUnitVoiceChannelUser(binaryMessage);
return new LCUnitToUnitVoiceChannelUser(message);
case UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED:
return new LCUnitToUnitVoiceChannelUserExtended(message);
case L3HARRIS_UNKNOWN_0A:
return new LCHarrisUnknownOpcode10(binaryMessage);
case L3HARRIS_RETURN_TO_CONTROL_CHANNEL:
return new LCHarrisReturnToControlChannel(message);
case L3HARRIS_UNKNOWN_2A:
return new LCHarrisUnknownOpcode42(binaryMessage);
return new LCHarrisUnknownOpcode42(message);
case L3HARRIS_UNKNOWN_2B:
return new LCHarrisUnknownOpcode43(binaryMessage);
return new LCHarrisUnknownOpcode43(message);
case L3HARRIS_UNKNOWN:
return new UnknownLinkControlWord(binaryMessage);
return new UnknownLinkControlWord(message);
case MOTOROLA_PATCH_GROUP_ADD:
return new LCMotorolaPatchGroupAdd(binaryMessage);
case MOTOROLA_PATCH_GROUP_DELETE:
return new LCMotorolaPatchGroupDelete(binaryMessage);
case MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_USER:
return new LCMotorolaPatchGroupVoiceChannelUser(binaryMessage);
case MOTOROLA_GROUP_REGROUP_ADD:
return new LCMotorolaGroupRegroupAdd(message);
case MOTOROLA_GROUP_REGROUP_DELETE:
return new LCMotorolaGroupGroupDelete(message);
case MOTOROLA_GROUP_REGROUP_VOICE_CHANNEL_USER:
return new LCMotorolaGroupRegroupVoiceChannelUser(message);
case MOTOROLA_TALK_COMPLETE:
return new LCMotorolaTalkComplete(binaryMessage);
case MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_UPDATE:
return new LCMotorolaPatchGroupVoiceChannelUpdate(binaryMessage);
return new LCMotorolaTalkComplete(message);
case MOTOROLA_GROUP_REGROUP_VOICE_CHANNEL_UPDATE:
return new LCMotorolaGroupRegroupVoiceChannelUpdate(message);
case MOTOROLA_UNIT_GPS:
return new LCMotorolaUnitGPS(binaryMessage);
return new LCMotorolaUnitGPS(message);
case MOTOROLA_RADIO_REPROGRAM_HEADER:
return new LCMotorolaRadioReprogramHeader(message);
case MOTOROLA_RADIO_REPROGRAM_RECORD:
return new LCMotorolaRadioReprogramRecord(message);
case MOTOROLA_EMERGENCY_ALARM_ACTIVATION:
return new LCMotorolaEmergencyAlarmActivation(message);
case MOTOROLA_UNKNOWN:
return new LCMotorolaUnknownOpcode(binaryMessage);
return new LCMotorolaUnknownOpcode(message);
default:
return new UnknownLinkControlWord(binaryMessage);
return new UnknownLinkControlWord(message);
}
}
}

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,14 +14,13 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.identifier.Identifier;
import java.util.Collections;
import java.util.List;
@@ -36,7 +34,7 @@ public class UnknownLinkControlWord extends LinkControlWord
*
* @param message
*/
public UnknownLinkControlWord(BinaryMessage message)
public UnknownLinkControlWord(CorrectedBinaryMessage message)
{
super(message);
}

View File

@@ -0,0 +1,57 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.module.decode.p25.IServiceOptionsProvider;
import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions;
/**
* Base voice call link control word
*/
public abstract class VoiceLinkControlMessage extends LinkControlWord implements IServiceOptionsProvider
{
private static final IntField SERVICE_OPTIONS = IntField.length8(OCTET_2_BIT_16);
private VoiceServiceOptions mVoiceServiceOptions;
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public VoiceLinkControlMessage(CorrectedBinaryMessage message)
{
super(message);
}
/**
* Service Options for this channel
*/
public VoiceServiceOptions getServiceOptions()
{
if(mVoiceServiceOptions == null)
{
mVoiceServiceOptions = new VoiceServiceOptions(getInt(SERVICE_OPTIONS));
}
return mVoiceServiceOptions;
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,7 +19,8 @@
package io.github.dsheirer.module.decode.p25.phase1.message.lc.l3harris;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.radio.RadioIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
@@ -28,20 +29,30 @@ import java.util.ArrayList;
import java.util.List;
/**
* L3Harris Unknown Opcode 10 (0x0A)
* L3Harris Opcode 10 (0x0A) - This seems to be a 'return to control channel' or 'private data call paging'.
* <p>
* Observed in a traffic channel carried by a TDU during an SNDCP packet data session. The controller send an 'All
* blocks received' PDU to the radio in the middle of a stream of these TDU/LC messages and the traffic channel ended
* with Call Termination TDULC messages. So, this may be some form of current data session user information update.
* Observed on a phase 1 traffic data channel carried by a TDU during an SNDCP packet data session. The controller sent
* an 'All blocks received' PDU to the radio and an 'Activate TDS context' in the middle of a stream of these TDU/LC
* messages, and then the radio terminated the traffic channel. So, this may be some form of return to control
* channel or maybe a private data call paging where the mobile returns to the control channel to receive the private
* data channel grant for another data call
*
* When the radio returned to the control channel, control sent the following two MAC messages on the Phase 2 control:
* LOCCH-U NAC:9/x009 SIGNAL CUSTOM/UNKNOWN VENDOR:HARRIS ID:A4 OPCODE:160 LENGTH:9 MSG:A0A409AC0312014871 (radio 0x014871 go to data channel 0x0312??)
* LOCCH-U NAC:9/x009 SIGNAL CUSTOM/UNKNOWN VENDOR:HARRIS ID:A4 OPCODE:172 LENGTH:12 MSG:ACA40C000312014871980418 (from 0x014871 to 0x980418 unit-2-unit data channel grant?)
*
* Both messages seem to refer to channel 0-786 (0x0312) so this may be a unit-2-unit private Phase 1 call or maybe
* a private data call. Radio addresses: 0x014871 and 0x980418
*
* In a second observation (Rockwall, TX), the control channel used the SNDCP data channel grant to send the
* mobile to the data channel and then the data channel transmitted a sequence of TDULCs containing only this message.
*
*/
public class LCHarrisUnknownOpcode10 extends LinkControlWord
public class LCHarrisReturnToControlChannel extends LinkControlWord
{
private static final int[] UNKNOWN_1 = {16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] TARGET_RADIO = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47};
private static final int[] SOURCE_RADIO = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
66, 67, 68, 69, 70, 71};
private static final IntField UNKNOWN_1 = IntField.length8(OCTET_2_BIT_16);
private static final IntField SOURCE_RADIO = IntField.length24(OCTET_3_BIT_24);
private static final IntField TARGET_RADIO = IntField.length24(OCTET_6_BIT_48);
private RadioIdentifier mSourceRadio;
private RadioIdentifier mTargetRadio;
private List<Identifier> mIdentifiers;
@@ -51,7 +62,7 @@ public class LCHarrisUnknownOpcode10 extends LinkControlWord
*
* @param message
*/
public LCHarrisUnknownOpcode10(BinaryMessage message)
public LCHarrisReturnToControlChannel(CorrectedBinaryMessage message)
{
super(message);
}
@@ -71,7 +82,7 @@ public class LCHarrisUnknownOpcode10 extends LinkControlWord
}
else
{
sb.append("L3HARRIS UNKNOWN OPCODE 10 ");
sb.append("L3HARRIS RETURN TO CONTROL CHANNEL OR PRIVATE DATA CALL PAGING");
sb.append(" FM:").append(getSourceRadio());
sb.append(" TO:").append(getTargetRadio());
sb.append(" UNK:").append(getUnknown());
@@ -82,7 +93,7 @@ public class LCHarrisUnknownOpcode10 extends LinkControlWord
public String getUnknown()
{
return getMessage().getHex(UNKNOWN_1, 2);
return getMessage().getHex(UNKNOWN_1);
}
/**
@@ -92,7 +103,7 @@ public class LCHarrisUnknownOpcode10 extends LinkControlWord
{
if(mSourceRadio == null)
{
mSourceRadio = APCO25RadioIdentifier.createFrom(getMessage().getInt(SOURCE_RADIO));
mSourceRadio = APCO25RadioIdentifier.createFrom(getInt(SOURCE_RADIO));
}
return mSourceRadio;
@@ -105,7 +116,7 @@ public class LCHarrisUnknownOpcode10 extends LinkControlWord
{
if(mTargetRadio == null)
{
mTargetRadio = APCO25RadioIdentifier.createTo(getMessage().getInt(TARGET_RADIO));
mTargetRadio = APCO25RadioIdentifier.createTo(getInt(TARGET_RADIO));
}
return mTargetRadio;

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
package io.github.dsheirer.module.decode.p25.phase1.message.lc.l3harris;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.Collections;
@@ -38,7 +38,7 @@ public class LCHarrisUnknownOpcode42 extends LinkControlWord
*
* @param message
*/
public LCHarrisUnknownOpcode42(BinaryMessage message)
public LCHarrisUnknownOpcode42(CorrectedBinaryMessage message)
{
super(message);
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
package io.github.dsheirer.module.decode.p25.phase1.message.lc.l3harris;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.Collections;
@@ -38,7 +38,7 @@ public class LCHarrisUnknownOpcode43 extends LinkControlWord
*
* @param message
*/
public LCHarrisUnknownOpcode43(BinaryMessage message)
public LCHarrisUnknownOpcode43(CorrectedBinaryMessage message)
{
super(message);
}

View File

@@ -0,0 +1,134 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.radio.RadioIdentifier;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
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.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
/**
* Motorola Link Control Opcode 10 appears to be an Emergency Alarm Activation message.
*
* This was observed in the following sequence:
* 1. Radio registers on network.
* 2. Radio assigned group and affiliation group
* 3. Network acknowledges radio's emergency alarm request
* 4. Network sends this message, interspersed with the ack message (3)
* 5. Network grants emergency group voice channel to radio and the same talkgroup references in this message, which
* is also the assigned talkgroup during initial registration.
* 6. Network grants second non-emerg group voice channel to radio and a second (unknown 0x39) talkgroup that may be
* a supervisor talkgroup.
*
* This link control message was also transmitted on active traffic channels.
*
* Note: the same opcode is used on both on control channel TSBK and traffic channel LCW messaging.
*/
public class LCMotorolaEmergencyAlarmActivation extends LinkControlWord
{
private static final IntField GROUP_ADDRESS = IntField.length16(OCTET_2_BIT_16);
//There seems to be room for another group address here, octets 4/5??
private static final IntField SOURCE_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private TalkgroupIdentifier mGroupAddress;
private RadioIdentifier mSourceAddress;
private List<Identifier> mIdentifiers;
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCMotorolaEmergencyAlarmActivation(CorrectedBinaryMessage message)
{
super(message);
}
public String toString()
{
StringBuilder sb = new StringBuilder();
if(!isValid())
{
sb.append("**CRC-FAILED** ");
}
if(isEncrypted())
{
sb.append(" ENCRYPTED");
}
else
{
sb.append("MOTOROLA EMERGENCY ALARM ACTIVATION RADIO:").append(getSourceAddress());
sb.append(" TALKGROUP:").append(getGroupAddress());
sb.append(" MSG:").append(getMessage().toHexString());
}
return sb.toString();
}
/**
* Source Address that activated the emergency alarm.
*/
public RadioIdentifier getSourceAddress()
{
if(mSourceAddress == null)
{
mSourceAddress = APCO25RadioIdentifier.createTo(getInt(SOURCE_ADDRESS));
}
return mSourceAddress;
}
/**
* Talkgroup to be activated for the emergency voice call
*/
public TalkgroupIdentifier getGroupAddress()
{
if(mGroupAddress == null)
{
mGroupAddress = APCO25Talkgroup.create(getInt(GROUP_ADDRESS));
}
return mGroupAddress;
}
/**
* List of identifiers contained in this message
*/
@Override
public List<Identifier> getIdentifiers()
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getGroupAddress());
mIdentifiers.add(getSourceAddress());
}
return mIdentifiers;
}
}

View File

@@ -0,0 +1,144 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.patch.PatchGroup;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.patch.APCO25PatchGroup;
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
/**
* Motorola Group Regroup Delete
*/
public class LCMotorolaGroupGroupDelete extends LinkControlWord
{
private static final IntField SUPERGROUP = IntField.length16(OCTET_2_BIT_16);
private static final IntField PATCHED_GROUP_1 = IntField.length16(OCTET_4_BIT_32);
private static final IntField PATCHED_GROUP_2 = IntField.length16(OCTET_6_BIT_48);
private APCO25PatchGroup mSuperGroup;
private TalkgroupIdentifier mPatchedGroup1;
private TalkgroupIdentifier mPatchedGroup2;
private List<Identifier> mIdentifiers;
public LCMotorolaGroupGroupDelete(CorrectedBinaryMessage message)
{
super(message);
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("MOTOROLA GROUP REGROUP DELETE SUPERGROUP:").append(getSuperGroup());
return sb.toString();
}
/**
* Patch Group
*/
public Identifier getSuperGroup()
{
if(mSuperGroup == null)
{
PatchGroup patchGroup = new PatchGroup(APCO25Talkgroup.create(getInt(SUPERGROUP)));
patchGroup.addPatchedTalkgroups(getPatchedGroups());
mSuperGroup = APCO25PatchGroup.create(patchGroup);
}
return mSuperGroup;
}
public List<TalkgroupIdentifier> getPatchedGroups()
{
List<TalkgroupIdentifier> patchedGroups = new ArrayList<>();
if(hasPatchedGroup1())
{
patchedGroups.add(getPatchedGroup1());
}
if(hasPatchedGroup2())
{
patchedGroups.add(getPatchedGroup2());
}
return patchedGroups;
}
/**
* Patched Group 1
*/
public TalkgroupIdentifier getPatchedGroup1()
{
if(mPatchedGroup1 == null)
{
mPatchedGroup1 = APCO25Talkgroup.create(getInt(PATCHED_GROUP_1));
}
return mPatchedGroup1;
}
public boolean hasPatchedGroup1()
{
return getInt(PATCHED_GROUP_1) != 0 &&
(getInt(SUPERGROUP) != getInt(PATCHED_GROUP_1));
}
/**
* Patched Group 2
*/
public TalkgroupIdentifier getPatchedGroup2()
{
if(mPatchedGroup2 == null)
{
mPatchedGroup2 = APCO25Talkgroup.create(getInt(PATCHED_GROUP_2));
}
return mPatchedGroup2;
}
public boolean hasPatchedGroup2()
{
return getInt(PATCHED_GROUP_2) != 0 &&
(getInt(SUPERGROUP) != getInt(PATCHED_GROUP_2));
}
/**
* List of identifiers contained in this message
*/
@Override
public List<Identifier> getIdentifiers()
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getSuperGroup());
}
return mIdentifiers;
}
}

View File

@@ -1,49 +1,50 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.patch.PatchGroup;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.patch.APCO25PatchGroup;
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
public class LCMotorolaPatchGroupAdd extends MotorolaLinkControlWord
/**
* Motorola Group Regroup Add
*/
public class LCMotorolaGroupRegroupAdd extends LinkControlWord
{
private static final int[] PATCH_GROUP = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
private static final int[] PATCHED_GROUP_1 = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] PATCHED_GROUP_2 = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
private static final IntField SUPERGROUP = IntField.length16(OCTET_2_BIT_16);
private static final IntField PATCHED_GROUP_1 = IntField.length16(OCTET_4_BIT_32);
private static final IntField PATCHED_GROUP_2 = IntField.length16(OCTET_6_BIT_48);
private APCO25PatchGroup mPatchGroup;
private TalkgroupIdentifier mPatchedGroup1;
private TalkgroupIdentifier mPatchedGroup2;
private List<Identifier> mIdentifiers;
public LCMotorolaPatchGroupAdd(BinaryMessage message)
public LCMotorolaGroupRegroupAdd(CorrectedBinaryMessage message)
{
super(message);
}
@@ -52,9 +53,7 @@ public class LCMotorolaPatchGroupAdd extends MotorolaLinkControlWord
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("MOTOROLA ADD PATCH GROUP:").append(getPatchGroup());
sb.append(" MSG:").append(getMessage().toHexString());
sb.append("MOTOROLA GROUP REGROUP ADD SUPERGROUP:").append(getPatchGroup());
return sb.toString();
}
@@ -65,7 +64,7 @@ public class LCMotorolaPatchGroupAdd extends MotorolaLinkControlWord
{
if(mPatchGroup == null)
{
PatchGroup patchGroup = new PatchGroup(APCO25Talkgroup.create(getMessage().getInt(PATCH_GROUP)));
PatchGroup patchGroup = new PatchGroup(APCO25Talkgroup.create(getInt(SUPERGROUP)));
patchGroup.addPatchedTalkgroups(getPatchedGroups());
mPatchGroup = APCO25PatchGroup.create(patchGroup);
}
@@ -97,7 +96,7 @@ public class LCMotorolaPatchGroupAdd extends MotorolaLinkControlWord
{
if(mPatchedGroup1 == null)
{
mPatchedGroup1 = APCO25Talkgroup.create(getMessage().getInt(PATCHED_GROUP_1));
mPatchedGroup1 = APCO25Talkgroup.create(getInt(PATCHED_GROUP_1));
}
return mPatchedGroup1;
@@ -105,8 +104,8 @@ public class LCMotorolaPatchGroupAdd extends MotorolaLinkControlWord
public boolean hasPatchedGroup1()
{
return getMessage().getInt(PATCHED_GROUP_1) != 0 &&
(getMessage().getInt(PATCH_GROUP) != getMessage().getInt(PATCHED_GROUP_1));
return getInt(PATCHED_GROUP_1) != 0 &&
(getInt(SUPERGROUP) != getInt(PATCHED_GROUP_1));
}
/**
@@ -116,7 +115,7 @@ public class LCMotorolaPatchGroupAdd extends MotorolaLinkControlWord
{
if(mPatchedGroup2 == null)
{
mPatchedGroup2 = APCO25Talkgroup.create(getMessage().getInt(PATCHED_GROUP_2));
mPatchedGroup2 = APCO25Talkgroup.create(getInt(PATCHED_GROUP_2));
}
return mPatchedGroup2;
@@ -124,8 +123,7 @@ public class LCMotorolaPatchGroupAdd extends MotorolaLinkControlWord
public boolean hasPatchedGroup2()
{
return getMessage().getInt(PATCHED_GROUP_2) != 0 &&
(getMessage().getInt(PATCH_GROUP) != getMessage().getInt(PATCHED_GROUP_2));
return getInt(PATCHED_GROUP_2) != 0 && (getInt(SUPERGROUP) != getInt(PATCHED_GROUP_2));
}
/**

View File

@@ -0,0 +1,103 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.patch.PatchGroup;
import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel;
import io.github.dsheirer.module.decode.p25.identifier.patch.APCO25PatchGroup;
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.VoiceLinkControlMessage;
import java.util.Collections;
import java.util.List;
/**
* Motorola Group Regroup Voice Channel Update
*/
public class LCMotorolaGroupRegroupVoiceChannelUpdate extends VoiceLinkControlMessage implements IFrequencyBandReceiver
{
private static final IntField SUPER_GROUP = IntField.length16(OCTET_3_BIT_24);
private static final IntField FREQUENCY_BAND = IntField.length4(OCTET_7_BIT_56);
private static final IntField CHANNEL_NUMBER = IntField.length12(OCTET_7_BIT_56 + 4);
private APCO25PatchGroup mSupergroupAddress;
private APCO25Channel mChannel;
private List<Identifier> mIdentifiers;
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCMotorolaGroupRegroupVoiceChannelUpdate(CorrectedBinaryMessage message)
{
super(message);
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("MOTOROLA GROUP REGROUP VOICE CHANNEL UPDATE");
sb.append(" SUPERGROUP:").append(getSupergroupAddress());
sb.append(" CHANNEL:").append(getChannel());
return sb.toString();
}
public APCO25PatchGroup getSupergroupAddress()
{
if(mSupergroupAddress == null)
{
PatchGroup patchGroup = new PatchGroup(APCO25Talkgroup.create(getInt(SUPER_GROUP)));
mSupergroupAddress = APCO25PatchGroup.create(patchGroup);
}
return mSupergroupAddress;
}
public APCO25Channel getChannel()
{
if(mChannel == null)
{
mChannel = APCO25Channel.create(getInt(FREQUENCY_BAND), getInt(CHANNEL_NUMBER));
}
return mChannel;
}
@Override
public List<Identifier> getIdentifiers()
{
if(mIdentifiers == null)
{
mIdentifiers = Collections.singletonList(getSupergroupAddress());
}
return mIdentifiers;
}
@Override
public List<IChannelDescriptor> getChannels()
{
return Collections.singletonList(getChannel());
}
}

View File

@@ -0,0 +1,103 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.patch.PatchGroup;
import io.github.dsheirer.module.decode.p25.identifier.patch.APCO25PatchGroup;
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.phase1.message.lc.VoiceLinkControlMessage;
import java.util.ArrayList;
import java.util.List;
/**
* Motorola Group Regroup Voice Channel User.
*/
public class LCMotorolaGroupRegroupVoiceChannelUser extends VoiceLinkControlMessage
{
private static final IntField SUPERGROUP_ADDRESS = IntField.length16(OCTET_4_BIT_32);
private static final IntField SOURCE_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private APCO25PatchGroup mSupergroupAddress;
private Identifier mSourceAddress;
private List<Identifier> mIdentifiers;
public LCMotorolaGroupRegroupVoiceChannelUser(CorrectedBinaryMessage message)
{
super(message);
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("MOTOROLA GROUP REGROUP VOICE CHANNEL USER FM:").append(getSourceAddress());
sb.append(" TO:").append(getSupergroupAddress());
sb.append(" ").append(getServiceOptions());
return sb.toString();
}
/**
* Supergroup (ie Patch group) address
*/
public APCO25PatchGroup getSupergroupAddress()
{
if(mSupergroupAddress == null)
{
PatchGroup patchGroup = new PatchGroup(APCO25Talkgroup.create(getInt(SUPERGROUP_ADDRESS)));
mSupergroupAddress = APCO25PatchGroup.create(patchGroup);
}
return mSupergroupAddress;
}
/**
* Source address
*/
public Identifier getSourceAddress()
{
if(mSourceAddress == null)
{
mSourceAddress = APCO25RadioIdentifier.createFrom(getInt(SOURCE_ADDRESS));
}
return mSourceAddress;
}
/**
* List of identifiers contained in this message
*/
@Override
public List<Identifier> getIdentifiers()
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getSupergroupAddress());
mIdentifiers.add(getSourceAddress());
}
return mIdentifiers;
}
}

View File

@@ -1,145 +0,0 @@
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
*
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.patch.PatchGroup;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.patch.APCO25PatchGroup;
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
import java.util.ArrayList;
import java.util.List;
public class LCMotorolaPatchGroupDelete extends MotorolaLinkControlWord
{
private static final int[] PATCH_GROUP = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
private static final int[] PATCHED_GROUP_1 = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] PATCHED_GROUP_2 = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
private APCO25PatchGroup mPatchGroup;
private TalkgroupIdentifier mPatchedGroup1;
private TalkgroupIdentifier mPatchedGroup2;
private List<Identifier> mIdentifiers;
public LCMotorolaPatchGroupDelete(BinaryMessage message)
{
super(message);
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("MOTOROLA DELETE PATCH GROUP:").append(getPatchGroup());
sb.append(" MSG:").append(getMessage().toHexString());
return sb.toString();
}
/**
* Patch Group
*/
public Identifier getPatchGroup()
{
if(mPatchGroup == null)
{
PatchGroup patchGroup = new PatchGroup(APCO25Talkgroup.create(getMessage().getInt(PATCH_GROUP)));
patchGroup.addPatchedTalkgroups(getPatchedGroups());
mPatchGroup = APCO25PatchGroup.create(patchGroup);
}
return mPatchGroup;
}
public List<TalkgroupIdentifier> getPatchedGroups()
{
List<TalkgroupIdentifier> patchedGroups = new ArrayList<>();
if(hasPatchedGroup1())
{
patchedGroups.add(getPatchedGroup1());
}
if(hasPatchedGroup2())
{
patchedGroups.add(getPatchedGroup2());
}
return patchedGroups;
}
/**
* Patched Group 1
*/
public TalkgroupIdentifier getPatchedGroup1()
{
if(mPatchedGroup1 == null)
{
mPatchedGroup1 = APCO25Talkgroup.create(getMessage().getInt(PATCHED_GROUP_1));
}
return mPatchedGroup1;
}
public boolean hasPatchedGroup1()
{
return getMessage().getInt(PATCHED_GROUP_1) != 0 &&
(getMessage().getInt(PATCH_GROUP) != getMessage().getInt(PATCHED_GROUP_1));
}
/**
* Patched Group 2
*/
public TalkgroupIdentifier getPatchedGroup2()
{
if(mPatchedGroup2 == null)
{
mPatchedGroup2 = APCO25Talkgroup.create(getMessage().getInt(PATCHED_GROUP_2));
}
return mPatchedGroup2;
}
public boolean hasPatchedGroup2()
{
return getMessage().getInt(PATCHED_GROUP_2) != 0 &&
(getMessage().getInt(PATCH_GROUP) != getMessage().getInt(PATCHED_GROUP_2));
}
/**
* List of identifiers contained in this message
*/
@Override
public List<Identifier> getIdentifiers()
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getPatchGroup());
}
return mIdentifiers;
}
}

View File

@@ -1,134 +0,0 @@
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
*
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.patch.PatchGroup;
import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel;
import io.github.dsheirer.module.decode.p25.identifier.patch.APCO25PatchGroup;
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import java.util.ArrayList;
import java.util.List;
/**
* Motorola Patch Group Voice Channel Update
*/
public class LCMotorolaPatchGroupVoiceChannelUpdate extends MotorolaLinkControlWord implements IFrequencyBandReceiver
{
private static final int[] UNKNOWN_1 = {16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] PATCH_GROUP = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] UNKNOWN_2 = {40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] UNKNOWN_3 = {48, 49, 50, 51, 52, 53, 54, 55};
private static final int[] FREQUENCY_BAND = {56, 57, 58, 59};
private static final int[] CHANNEL_NUMBER = {60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
private APCO25PatchGroup mPatchGroup;
private IChannelDescriptor mChannel;
private List<Identifier> mIdentifiers;
private List<IChannelDescriptor> mChannels;
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCMotorolaPatchGroupVoiceChannelUpdate(BinaryMessage message)
{
super(message);
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("MOTOROLA PATCH VOICE CHANNEL UPDATE");
sb.append(" PATCH GROUP:").append(getPatchGroup());
sb.append(" CHANNEL:").append(getChannel());
sb.append(" UNK1:").append(getUnknownField1());
sb.append(" UNK2:").append(getUnknownField2());
sb.append(" UNK3:").append(getUnknownField3());
sb.append(" MSG:").append(getMessage().toHexString());
return sb.toString();
}
public APCO25PatchGroup getPatchGroup()
{
if(mPatchGroup == null)
{
PatchGroup patchGroup = new PatchGroup(APCO25Talkgroup.create(getMessage().getInt(PATCH_GROUP)));
mPatchGroup = APCO25PatchGroup.create(patchGroup);
}
return mPatchGroup;
}
public IChannelDescriptor getChannel()
{
if(mChannel == null)
{
mChannel = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND), getMessage().getInt(CHANNEL_NUMBER));
}
return mChannel;
}
public String getUnknownField1()
{
return getMessage().getHex(UNKNOWN_1, 2);
}
public String getUnknownField2()
{
return getMessage().getHex(UNKNOWN_2, 2);
}
public String getUnknownField3()
{
return getMessage().getHex(UNKNOWN_3, 2);
}
@Override
public List<Identifier> getIdentifiers()
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getPatchGroup());
}
return mIdentifiers;
}
@Override
public List<IChannelDescriptor> getChannels()
{
if(mChannels == null)
{
mChannels = new ArrayList<>();
mChannels.add(getChannel());
}
return mChannels;
}
}

View File

@@ -1,120 +0,0 @@
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
*
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.patch.PatchGroup;
import io.github.dsheirer.module.decode.p25.identifier.patch.APCO25PatchGroup;
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.reference.VoiceServiceOptions;
import java.util.ArrayList;
import java.util.List;
public class LCMotorolaPatchGroupVoiceChannelUser extends MotorolaLinkControlWord
{
private static final int[] SERVICE_OPTIONS = {16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] PATCH_GROUP_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] SOURCE_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private VoiceServiceOptions mVoiceServiceOptions;
private APCO25PatchGroup mGroupAddress;
private Identifier mSourceAddress;
private List<Identifier> mIdentifiers;
public LCMotorolaPatchGroupVoiceChannelUser(BinaryMessage message)
{
super(message);
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("MOTOROLA PATCH GROUP VOICE CHANNEL USER FM:").append(getSourceAddress());
sb.append(" TO:").append(getGroupAddress());
sb.append(" ").append(getVoiceServiceOptions());
sb.append(" MSG:").append(getMessage().toHexString());
return sb.toString();
}
/**
* Service Options for this channel
*/
public VoiceServiceOptions getVoiceServiceOptions()
{
if(mVoiceServiceOptions == null)
{
mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS));
}
return mVoiceServiceOptions;
}
/**
* Talkgroup address
*/
public APCO25PatchGroup getGroupAddress()
{
if(mGroupAddress == null)
{
PatchGroup patchGroup = new PatchGroup(APCO25Talkgroup.create(getMessage().getInt(PATCH_GROUP_ADDRESS)));
mGroupAddress = APCO25PatchGroup.create(patchGroup);
}
return mGroupAddress;
}
/**
* Source address
*/
public Identifier getSourceAddress()
{
if(mSourceAddress == null)
{
mSourceAddress = APCO25RadioIdentifier.createFrom(getMessage().getInt(SOURCE_ADDRESS));
}
return mSourceAddress;
}
/**
* List of identifiers contained in this message
*/
@Override
public List<Identifier> getIdentifiers()
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getGroupAddress());
mIdentifiers.add(getSourceAddress());
}
return mIdentifiers;
}
}

View File

@@ -0,0 +1,155 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
/**
* Motorola Link Control Opcode 0x15.
*
* Note: I suspect this is some form of radio reprogramming message, possibly used to update encryption.
*
* I've seen LCOpcode 0x15 and 0x17 twice and in both cases it was sent in a TDULC at the end of a call for the same
* radio on the CNYICC system. The header references the talkgroup that the radio is calling, so it may be some form
* of dynamic regrouping, but the total content is quite large.
*
* Note: this seems to only be targeted to certain radios since it wasn't sent at the end of every call.
*
* Examples observed on traffic channels in TDULC at the end of a call following the Motorola Talk Complete message
* for Radio: 15,104,082 (0xE67852) and TG:7101 (0x1BBD)
* Example 1
*
* 1590 1BBD 07 0100 F 8BA / 1BBD=TG, 07=record count, 0100=?, F=sequence number, 8BA=crc checksum
* 1790 01 F BEE00 2AE E67 / BEE00=WACN, 2AE=SYS, E67...= RADIO ID
* 1790 02 F 852 83ED1081 / ...852=RADIO ID cont.
* 1790 03 F E33C03E9B3E
* 1790 04 F 35647DE0C00
* 1790 05 F C8A83E351E4
* 1790 06 F 079F592CF37
* 1790 07 F 94B30000000
*
* Example 2
* 1590 1BBD070100 4 955
* 1790 01 4 BEE002AEE67
* 1790 02 4 85283ED1081
* 1790 03 4 E33C03E9B3E
* 1790 04 4 35647DE0C00
* 1790 05 4 C8A83E351E4
* 1790 06 4 079F592CF37
* 1790 07 4 94B30000000
*
* The LCO 15 header starts with the Talkgroup value and seems to identify the count of continuation messages to
* follow (0x07). In the LCO 17 continuation messages, the first octet after the vendor seems to be a message record
* count ID, ranging from 1 to 7. The next nibble in the continuation messages seems to be a continuation message
* sequence number to let you know that the continuation messages are all part of the same sequence.
*
* The reprogramming payload sequence starts by sending the full SUID for the radio (BEE00.2AE.E67852).
*/
public class LCMotorolaRadioReprogramHeader extends LinkControlWord
{
private static final IntField TALKGROUP = IntField.length16(OCTET_2_BIT_16);
private static final IntField RECORD_COUNT = IntField.length8(OCTET_4_BIT_32);
private static final IntField SEQUENCE_NUMBER = IntField.length4(OCTET_7_BIT_56);
private static final IntField SEQUENCE_CHECKSUM = IntField.length12(OCTET_7_BIT_56 + 4);
private Identifier mTalkgroup;
private List<Identifier> mIdentifiers;
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCMotorolaRadioReprogramHeader(CorrectedBinaryMessage message)
{
super(message);
}
public String toString()
{
StringBuilder sb = new StringBuilder();
if(!isValid())
{
sb.append("**CRC-FAILED** ");
}
if(isEncrypted())
{
sb.append(" ENCRYPTED");
}
sb.append("MOTOROLA RADIO REPROGRAM HEADER");
sb.append(" TG:").append(getTalkgroup());
sb.append(" RECORD COUNT:").append(getRecordCount());
sb.append(" SEQUENCE:").append(getSequenceNumber());
sb.append(" MSG:").append(getMessage().toHexString());
return sb.toString();
}
/**
* Talkgroup
*/
public Identifier getTalkgroup()
{
if(mTalkgroup == null)
{
mTalkgroup = APCO25Talkgroup.create(getInt(TALKGROUP));
}
return mTalkgroup;
}
/**
* Count of continuation messages to follow
* @return
*/
public int getRecordCount()
{
return getInt(RECORD_COUNT);
}
/**
* Sequence number
*/
public int getSequenceNumber()
{
return getInt(SEQUENCE_NUMBER);
}
/**
* List of identifiers contained in this message
*/
@Override
public List<Identifier> getIdentifiers()
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getTalkgroup());
}
return mIdentifiers;
}
}

View File

@@ -0,0 +1,89 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.Collections;
import java.util.List;
/**
* Motorola Link Control opcode 0x17 (23). This is possibly a radio reprogramming record segment that is used
* in combination with LCO 0x15. See notes in header of LCMotorolaRadioReprogramHeader class.
*/
public class LCMotorolaRadioReprogramRecord extends LinkControlWord
{
private static final IntField RECORD_NUMBER = IntField.length8(OCTET_2_BIT_16);
private static final IntField SEQUENCE_NUMBER = IntField.length4(OCTET_3_BIT_24);
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCMotorolaRadioReprogramRecord(CorrectedBinaryMessage message)
{
super(message);
}
public String toString()
{
StringBuilder sb = new StringBuilder();
if(!isValid())
{
sb.append("**CRC-FAILED** ");
}
if(isEncrypted())
{
sb.append(" ENCRYPTED");
}
sb.append("MOTOROLA RADIO REPROGRAM RECORD:").append(getRecordNumber());
sb.append(" OF SEQUENCE:").append(getSequenceNumber());
sb.append(" MSG:").append(getMessage().toHexString());
return sb.toString();
}
/**
* Record number
*/
public int getRecordNumber()
{
return getInt(RECORD_NUMBER);
}
/**
* Sequence number
*/
public int getSequenceNumber()
{
return getInt(SEQUENCE_NUMBER);
}
@Override
public List<Identifier> getIdentifiers()
{
return Collections.emptyList();
}
}

View File

@@ -1,32 +1,29 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
@@ -35,10 +32,9 @@ import java.util.List;
*/
public class LCMotorolaTalkComplete extends LinkControlWord
{
private static final int[] UNKNOWN_FIELD_1 = {16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] UNKNOWN_FIELD_2 = {40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70, 71};
private static final IntField UNKNOWN_FIELD_1 = IntField.length8(OCTET_2_BIT_16);
private static final IntField UNKNOWN_FIELD_2 = IntField.length8(OCTET_2_BIT_16);
private static final IntField ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mAddress;
private List<Identifier> mIdentifiers;
@@ -48,7 +44,7 @@ public class LCMotorolaTalkComplete extends LinkControlWord
*
* @param message
*/
public LCMotorolaTalkComplete(BinaryMessage message)
public LCMotorolaTalkComplete(CorrectedBinaryMessage message)
{
super(message);
}
@@ -72,19 +68,18 @@ public class LCMotorolaTalkComplete extends LinkControlWord
sb.append(" BY:").append(getAddress());
sb.append(" UNK1:").append(getUnknownField1());
sb.append(" UNK2:").append(getUnknownField2());
sb.append(" MSG:").append(getMessage().toHexString());
}
return sb.toString();
}
public String getUnknownField1()
{
return getMessage().getHex(UNKNOWN_FIELD_1, 2);
return getMessage().getHex(UNKNOWN_FIELD_1);
}
public String getUnknownField2()
{
return getMessage().getHex(UNKNOWN_FIELD_2, 2);
return getMessage().getHex(UNKNOWN_FIELD_2);
}
/**
@@ -94,7 +89,7 @@ public class LCMotorolaTalkComplete extends LinkControlWord
{
if(mAddress == null)
{
mAddress = APCO25RadioIdentifier.createFrom(getMessage().getInt(ADDRESS));
mAddress = APCO25RadioIdentifier.createFrom(getInt(ADDRESS));
}
return mAddress;

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,30 +19,39 @@
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.FragmentedIntField;
import io.github.dsheirer.identifier.Identifier;
import java.util.Collections;
import io.github.dsheirer.module.decode.dmr.identifier.P25Location;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
import org.jdesktop.swingx.mapviewer.GeoPosition;
/**
* Motorola Unit Self-Reported GPS Location
*/
public class LCMotorolaUnitGPS extends MotorolaLinkControlWord
public class LCMotorolaUnitGPS extends LinkControlWord
{
private static final double LATITUDE_MULTIPLIER = 90.0 / 0x7FFFFF;
private static final double LONGITUDE_MULTIPLIER = 180.0 / 0x7FFFFF;
private static final int[] UNKNOWN = {16, 17, 18, 19, 20, 21, 22, 23};
private static final int LATITUDE_SIGN = 24;
private static final int[] LATITUDE = {25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
private static final FragmentedIntField LATITUDE = FragmentedIntField.of(25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47);
private static final int LONGITUDE_SIGN = 48;
private static final int[] LONGITUDE = {49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
private static final FragmentedIntField LONGITUDE = FragmentedIntField.of(49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71);
private P25Location mLocation;
private GeoPosition mGeoPosition;
private List<Identifier> mIdentifiers;
/**
* Constructs an instance
* @param message binary
*/
public LCMotorolaUnitGPS(BinaryMessage message)
public LCMotorolaUnitGPS(CorrectedBinaryMessage message)
{
super(message);
}
@@ -55,13 +64,41 @@ public class LCMotorolaUnitGPS extends MotorolaLinkControlWord
return sb.toString();
}
/**
* GPS Location
* @return location in decimal degrees
*/
public P25Location getLocation()
{
if(mLocation == null)
{
mLocation = P25Location.createFrom(getLatitude(), getLongitude());
}
return mLocation;
}
/**
* Geo position
* @return position
*/
public GeoPosition getGeoPosition()
{
if(mGeoPosition == null)
{
mGeoPosition = new GeoPosition(getLatitude(), getLongitude());
}
return mGeoPosition;
}
/**
* GPS Latitude value.
* @return value in decimal degrees
*/
public double getLatitude()
{
return getMessage().getInt(LATITUDE) * LATITUDE_MULTIPLIER * (getMessage().get(LATITUDE_SIGN) ? -1 : 1);
return getInt(LATITUDE) * LATITUDE_MULTIPLIER * (getMessage().get(LATITUDE_SIGN) ? -1 : 1);
}
/**
@@ -70,7 +107,7 @@ public class LCMotorolaUnitGPS extends MotorolaLinkControlWord
*/
public double getLongitude()
{
return getMessage().getInt(LONGITUDE) * LONGITUDE_MULTIPLIER * (getMessage().get(LONGITUDE_SIGN) ? -1 : 1);
return getInt(LONGITUDE) * LONGITUDE_MULTIPLIER * (getMessage().get(LONGITUDE_SIGN) ? -1 : 1);
}
/**
@@ -79,6 +116,12 @@ public class LCMotorolaUnitGPS extends MotorolaLinkControlWord
@Override
public List<Identifier> getIdentifiers()
{
return Collections.emptyList();
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getLocation());
}
return mIdentifiers;
}
}

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,28 +14,28 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.Collections;
import java.util.List;
/**
* Unknown link control word.
*/
public class LCMotorolaUnknownOpcode extends MotorolaLinkControlWord
public class LCMotorolaUnknownOpcode extends LinkControlWord
{
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCMotorolaUnknownOpcode(BinaryMessage message)
public LCMotorolaUnknownOpcode(CorrectedBinaryMessage message)
{
super(message);
}
@@ -51,7 +50,7 @@ public class LCMotorolaUnknownOpcode extends MotorolaLinkControlWord
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(" MOTOROLA UNKNOWN/UNRECOGNIZED OPCODE:").append(getOpcode());
sb.append(" MOTOROLA UNKNOWN OPCODE:").append(getOpcodeNumber());
sb.append(" MSG:").append(getMessage().toHexString());
return sb.toString();
}

View File

@@ -1,28 +1,26 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra;
@@ -33,7 +31,6 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass;
import java.util.ArrayList;
import java.util.List;
@@ -42,13 +39,13 @@ import java.util.List;
*/
public class LCAdjacentSiteStatusBroadcast extends LinkControlWord implements IFrequencyBandReceiver
{
private static final int[] LRA = {8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] SYSTEM = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
private static final int[] RFSS = {32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] SITE = {40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] FREQUENCY_BAND = {48, 49, 50, 51};
private static final int[] CHANNEL_NUMBER = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
private static final int[] SERVICE_CLASS = {64, 65, 66, 67, 68, 69, 70, 71};
private static final IntField LRA = IntField.length8(OCTET_1_BIT_8);
private static final IntField SYSTEM = IntField.length12(OCTET_2_BIT_16 + 4);
private static final IntField RFSS = IntField.length8(OCTET_4_BIT_32);
private static final IntField SITE = IntField.length8(OCTET_5_BIT_40);
private static final IntField FREQUENCY_BAND = IntField.length4(OCTET_6_BIT_48);
private static final IntField CHANNEL_NUMBER = IntField.length12(OCTET_6_BIT_48 + 4);
private static final IntField SERVICE_CLASS = IntField.length8(OCTET_8_BIT_64);
private List<Identifier> mIdentifiers;
private Identifier mLRA;
@@ -63,7 +60,7 @@ public class LCAdjacentSiteStatusBroadcast extends LinkControlWord implements IF
*
* @param message
*/
public LCAdjacentSiteStatusBroadcast(BinaryMessage message)
public LCAdjacentSiteStatusBroadcast(CorrectedBinaryMessage message)
{
super(message);
}
@@ -85,7 +82,7 @@ public class LCAdjacentSiteStatusBroadcast extends LinkControlWord implements IF
{
if(mLRA == null)
{
mLRA = APCO25Lra.create(getMessage().getInt(LRA));
mLRA = APCO25Lra.create(getInt(LRA));
}
return mLRA;
@@ -95,7 +92,7 @@ public class LCAdjacentSiteStatusBroadcast extends LinkControlWord implements IF
{
if(mSystem == null)
{
mSystem = APCO25System.create(getMessage().getInt(SYSTEM));
mSystem = APCO25System.create(getInt(SYSTEM));
}
return mSystem;
@@ -105,7 +102,7 @@ public class LCAdjacentSiteStatusBroadcast extends LinkControlWord implements IF
{
if(mRFSS == null)
{
mRFSS = APCO25Rfss.create(getMessage().getInt(RFSS));
mRFSS = APCO25Rfss.create(getInt(RFSS));
}
return mRFSS;
@@ -115,7 +112,7 @@ public class LCAdjacentSiteStatusBroadcast extends LinkControlWord implements IF
{
if(mSite == null)
{
mSite = APCO25Site.create(getMessage().getInt(SITE));
mSite = APCO25Site.create(getInt(SITE));
}
return mSite;
@@ -125,8 +122,7 @@ public class LCAdjacentSiteStatusBroadcast extends LinkControlWord implements IF
{
if(mChannel == null)
{
mChannel = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND),
getMessage().getInt(CHANNEL_NUMBER));
mChannel = APCO25Channel.create(getInt(FREQUENCY_BAND), getInt(CHANNEL_NUMBER));
}
return mChannel;
@@ -136,7 +132,7 @@ public class LCAdjacentSiteStatusBroadcast extends LinkControlWord implements IF
{
if(mSystemServiceClass == null)
{
mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS));
mSystemServiceClass = new SystemServiceClass(getInt(SERVICE_CLASS));
}
return mSystemServiceClass;

View File

@@ -1,28 +1,26 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra;
@@ -32,23 +30,23 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitCha
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Secondary control channel broadcast explicit information for V/UHF channels
* Adjacent site status broadcast (ie neighbor).
*/
public class LCAdjacentSiteStatusBroadcastExplicit extends LinkControlWord implements IFrequencyBandReceiver
{
private static final int[] LRA = {8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] DOWNLINK_FREQUENCY_BAND = {16, 17, 18, 19};
private static final int[] DOWNLINK_CHANNEL_NUMBER = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
private static final int[] RFSS = {32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] SITE = {40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] UPLINK_FREQUENCY_BAND = {48, 49, 50, 51};
private static final int[] UPLINK_CHANNEL_NUMBER = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
private static final int[] SERVICE_CLASS = {64, 65, 66, 67, 68, 69, 70, 71};
private static final IntField LRA = IntField.length8(OCTET_1_BIT_8);
private static final IntField DOWNLINK_FREQUENCY_BAND = IntField.length4(OCTET_2_BIT_16);
private static final IntField DOWNLINK_CHANNEL_NUMBER = IntField.length12(OCTET_2_BIT_16 + 4);
private static final IntField RFSS = IntField.length8(OCTET_4_BIT_32);
private static final IntField SITE = IntField.length8(OCTET_5_BIT_40);
private static final IntField UPLINK_FREQUENCY_BAND = IntField.length4(OCTET_6_BIT_48);
private static final IntField UPLINK_CHANNEL_NUMBER = IntField.length12(OCTET_6_BIT_48 + 4);
private static final IntField SERVICE_CLASS = IntField.length8(OCTET_8_BIT_64);
private List<Identifier> mIdentifiers;
private Identifier mLRA;
@@ -62,7 +60,7 @@ public class LCAdjacentSiteStatusBroadcastExplicit extends LinkControlWord imple
*
* @param message
*/
public LCAdjacentSiteStatusBroadcastExplicit(BinaryMessage message)
public LCAdjacentSiteStatusBroadcastExplicit(CorrectedBinaryMessage message)
{
super(message);
}
@@ -83,7 +81,7 @@ public class LCAdjacentSiteStatusBroadcastExplicit extends LinkControlWord imple
{
if(mLRA == null)
{
mLRA = APCO25Lra.create(getMessage().getInt(LRA));
mLRA = APCO25Lra.create(getInt(LRA));
}
return mLRA;
@@ -93,7 +91,7 @@ public class LCAdjacentSiteStatusBroadcastExplicit extends LinkControlWord imple
{
if(mRFSS == null)
{
mRFSS = APCO25Rfss.create(getMessage().getInt(RFSS));
mRFSS = APCO25Rfss.create(getInt(RFSS));
}
return mRFSS;
@@ -103,7 +101,7 @@ public class LCAdjacentSiteStatusBroadcastExplicit extends LinkControlWord imple
{
if(mSite == null)
{
mSite = APCO25Site.create(getMessage().getInt(SITE));
mSite = APCO25Site.create(getInt(SITE));
}
return mSite;
@@ -113,9 +111,8 @@ public class LCAdjacentSiteStatusBroadcastExplicit extends LinkControlWord imple
{
if(mChannel == null)
{
mChannel = APCO25ExplicitChannel.create(getMessage().getInt(DOWNLINK_FREQUENCY_BAND),
getMessage().getInt(DOWNLINK_CHANNEL_NUMBER), getMessage().getInt(UPLINK_FREQUENCY_BAND),
getMessage().getInt(UPLINK_CHANNEL_NUMBER));
mChannel = APCO25ExplicitChannel.create(getInt(DOWNLINK_FREQUENCY_BAND), getInt(DOWNLINK_CHANNEL_NUMBER),
getInt(UPLINK_FREQUENCY_BAND), getInt(UPLINK_CHANNEL_NUMBER));
}
return mChannel;
@@ -125,7 +122,7 @@ public class LCAdjacentSiteStatusBroadcastExplicit extends LinkControlWord imple
{
if(mSystemServiceClass == null)
{
mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS));
mSystemServiceClass = new SystemServiceClass(getInt(SERVICE_CLASS));
}
return mSystemServiceClass;
@@ -152,8 +149,6 @@ public class LCAdjacentSiteStatusBroadcastExplicit extends LinkControlWord imple
@Override
public List<IChannelDescriptor> getChannels()
{
List<IChannelDescriptor> channels = new ArrayList<>();
channels.add(getChannel());
return channels;
return Collections.singletonList(getChannel());
}
}

View File

@@ -1,32 +1,29 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
@@ -35,12 +32,8 @@ import java.util.List;
*/
public class LCCallAlert extends LinkControlWord
{
private static final int[] RESERVED = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] TARGET_ADDRESS = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47};
private static final int[] SOURCE_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_3_BIT_24);
private static final IntField SOURCE_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mTargetAddress;
private Identifier mSourceAddress;
private List<Identifier> mIdentifiers;
@@ -50,7 +43,7 @@ public class LCCallAlert extends LinkControlWord
*
* @param message
*/
public LCCallAlert(BinaryMessage message)
public LCCallAlert(CorrectedBinaryMessage message)
{
super(message);
}
@@ -71,7 +64,7 @@ public class LCCallAlert extends LinkControlWord
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getMessage().getInt(TARGET_ADDRESS));
mTargetAddress = APCO25RadioIdentifier.createTo(getInt(TARGET_ADDRESS));
}
return mTargetAddress;
@@ -84,7 +77,7 @@ public class LCCallAlert extends LinkControlWord
{
if(mSourceAddress == null)
{
mSourceAddress = APCO25RadioIdentifier.createFrom(getMessage().getInt(SOURCE_ADDRESS));
mSourceAddress = APCO25RadioIdentifier.createFrom(getInt(SOURCE_ADDRESS));
}
return mSourceAddress;

View File

@@ -1,32 +1,29 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
@@ -37,10 +34,7 @@ public class LCCallTermination extends LinkControlWord
{
private static final int MOTOROLA_SYSTEM_CONTROLLER = 0xFFFFFD;
private static final int HARRIS_SYSTEM_CONTROLLER = 0;
private static final int[] ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70, 71};
private static final IntField ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mAddress;
private List<Identifier> mIdentifiers;
@@ -49,7 +43,7 @@ public class LCCallTermination extends LinkControlWord
*
* @param message
*/
public LCCallTermination(BinaryMessage message)
public LCCallTermination(CorrectedBinaryMessage message)
{
super(message);
}
@@ -69,7 +63,7 @@ public class LCCallTermination extends LinkControlWord
{
if(mAddress == null)
{
mAddress = APCO25Talkgroup.create(getMessage().getInt(ADDRESS));
mAddress = APCO25Talkgroup.create(getInt(ADDRESS));
}
return mAddress;
@@ -80,7 +74,7 @@ public class LCCallTermination extends LinkControlWord
*/
public boolean isNetworkCommandedTeardown()
{
int address = getMessage().getInt(ADDRESS);
int address = getInt(ADDRESS);
return address == MOTOROLA_SYSTEM_CONTROLLER || address == HARRIS_SYSTEM_CONTROLLER;
}

View File

@@ -1,54 +1,52 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.FragmentedIntField;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.bits.LongField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.Collections;
import java.util.List;
/**
* Echo of the status update from a subscriber when the destination of the update is another subscriber unit.
* Channel identifier update
*/
public class LCFrequencyBandUpdate extends LinkControlWord implements IFrequencyBand
public class LCChannelIdentifierUpdate extends LinkControlWord implements IFrequencyBand
{
private static final int[] FREQUENCY_BAND_IDENTIFIER = {8, 9, 10, 11};
private static final int[] BANDWIDTH = {12, 13, 14, 15, 16, 17, 18, 19, 20};
private static final IntField FREQUENCY_BAND_IDENTIFIER = IntField.length4(OCTET_1_BIT_8);
private static final FragmentedIntField BANDWIDTH = FragmentedIntField.of(12, 13, 14, 15, 16, 17, 18, 19, 20);
private static final int TRANSMIT_OFFSET_SIGN = 21;
private static final int[] TRANSMIT_OFFSET = {22, 23, 24, 25, 26, 27, 28, 29};
private static final int[] CHANNEL_SPACING = {30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] BASE_FREQUENCY = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private static final FragmentedIntField TRANSMIT_OFFSET = FragmentedIntField.of(22, 23, 24, 25, 26, 27, 28, 29);
private static final FragmentedIntField CHANNEL_SPACING = FragmentedIntField.of(30, 31, 32, 33, 34, 35, 36, 37, 38, 39);
private static final LongField BASE_FREQUENCY = LongField.length32(OCTET_5_BIT_40);
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCFrequencyBandUpdate(BinaryMessage message)
public LCChannelIdentifierUpdate(CorrectedBinaryMessage message)
{
super(message);
}
@@ -68,31 +66,31 @@ public class LCFrequencyBandUpdate extends LinkControlWord implements IFrequency
@Override
public int getIdentifier()
{
return getMessage().getInt(FREQUENCY_BAND_IDENTIFIER);
return getInt(FREQUENCY_BAND_IDENTIFIER);
}
@Override
public long getChannelSpacing()
{
return getMessage().getInt(CHANNEL_SPACING) * 125l;
return getInt(CHANNEL_SPACING) * 125l;
}
@Override
public long getBaseFrequency()
{
return getMessage().getLong(BASE_FREQUENCY) * 5l;
return getLong(BASE_FREQUENCY) * 5l;
}
@Override
public int getBandwidth()
{
return getMessage().getInt(BANDWIDTH) * 125;
return getInt(BANDWIDTH) * 125;
}
@Override
public long getTransmitOffset()
{
long offset = getMessage().getLong(TRANSMIT_OFFSET) * getChannelSpacing();
long offset = getInt(TRANSMIT_OFFSET) * getChannelSpacing();
if(!getMessage().get(TRANSMIT_OFFSET_SIGN))
{
@@ -107,7 +105,7 @@ public class LCFrequencyBandUpdate extends LinkControlWord implements IFrequency
*/
public boolean hasTransmitOffset()
{
return getMessage().getInt(TRANSMIT_OFFSET) != 0x80;
return getInt(TRANSMIT_OFFSET) != 0x80;
}
@Override

View File

@@ -1,54 +1,52 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.FragmentedIntField;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.bits.LongField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.Collections;
import java.util.List;
/**
* Identifier update explicit
* Channel identifier update VHF/UHF
*/
public class LCFrequencyBandUpdateExplicit extends LinkControlWord implements IFrequencyBand
public class LCChannelIdentifierUpdateVU extends LinkControlWord implements IFrequencyBand
{
private static final int[] FREQUENCY_BAND_IDENTIFIER = {8, 9, 10, 11};
private static final int[] BANDWIDTH = {12, 13, 14, 15};
private static final IntField FREQUENCY_BAND_IDENTIFIER = IntField.length4(OCTET_1_BIT_8);
private static final IntField BANDWIDTH = IntField.length4(OCTET_1_BIT_8 + 4);
private static final int TRANSMIT_OFFSET_SIGN = 16;
private static final int[] TRANSMIT_OFFSET = {17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29};
private static final int[] CHANNEL_SPACING = {30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] BASE_FREQUENCY = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
private static final FragmentedIntField TRANSMIT_OFFSET = FragmentedIntField.of(17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29);
private static final FragmentedIntField CHANNEL_SPACING = FragmentedIntField.of(30, 31, 32, 33, 34, 35, 36, 37, 38, 39);
private static final LongField BASE_FREQUENCY = LongField.length32(OCTET_5_BIT_40);
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCFrequencyBandUpdateExplicit(BinaryMessage message)
public LCChannelIdentifierUpdateVU(CorrectedBinaryMessage message)
{
super(message);
}
@@ -68,25 +66,25 @@ public class LCFrequencyBandUpdateExplicit extends LinkControlWord implements IF
@Override
public int getIdentifier()
{
return getMessage().getInt(FREQUENCY_BAND_IDENTIFIER);
return getInt(FREQUENCY_BAND_IDENTIFIER);
}
@Override
public long getChannelSpacing()
{
return getMessage().getInt(CHANNEL_SPACING) * 125l;
return getInt(CHANNEL_SPACING) * 125l;
}
@Override
public long getBaseFrequency()
{
return getMessage().getLong(BASE_FREQUENCY) * 5l;
return getLong(BASE_FREQUENCY) * 5l;
}
@Override
public int getBandwidth()
{
int bandwidth = getMessage().getInt(BANDWIDTH);
int bandwidth = getInt(BANDWIDTH);
if(bandwidth == 0x4)
{
@@ -103,7 +101,7 @@ public class LCFrequencyBandUpdateExplicit extends LinkControlWord implements IF
@Override
public long getTransmitOffset()
{
long offset = getMessage().getLong(TRANSMIT_OFFSET) * getChannelSpacing();
long offset = getInt(TRANSMIT_OFFSET) * getChannelSpacing();
if(!getMessage().get(TRANSMIT_OFFSET_SIGN))
{
@@ -118,7 +116,7 @@ public class LCFrequencyBandUpdateExplicit extends LinkControlWord implements IF
*/
public boolean hasTransmitOffset()
{
return getMessage().getInt(TRANSMIT_OFFSET) != 0x80;
return getInt(TRANSMIT_OFFSET) != 0x80;
}

View File

@@ -0,0 +1,105 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.Collections;
import java.util.List;
/**
* Conventional fallback sent on the outbound channel to indicate that the repeater sending it is providing conventional
* fallback service and to indicate which users should use it.
*/
public class LCConventionalFallback extends LinkControlWord
{
private static final IntField FALLBACK_CHANNEL_ID_1 = IntField.length8(OCTET_3_BIT_24);
private static final IntField FALLBACK_CHANNEL_ID_2 = IntField.length8(OCTET_4_BIT_32);
private static final IntField FALLBACK_CHANNEL_ID_3 = IntField.length8(OCTET_5_BIT_40);
private static final IntField FALLBACK_CHANNEL_ID_4 = IntField.length8(OCTET_6_BIT_48);
private static final IntField FALLBACK_CHANNEL_ID_5 = IntField.length8(OCTET_7_BIT_56);
private static final IntField FALLBACK_CHANNEL_ID_6 = IntField.length8(OCTET_8_BIT_64);
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCConventionalFallback(CorrectedBinaryMessage message)
{
super(message);
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
if(!isValid())
{
sb.append(" [CRC ERROR]");
}
sb.append(" CONVENTIONAL FALLBACK CHANNELS 1:").append(getFallbackChannel1());
sb.append(" 2:").append(getFallbackChannel2());
sb.append(" 3:").append(getFallbackChannel3());
sb.append(" 4:").append(getFallbackChannel4());
sb.append(" 5:").append(getFallbackChannel5());
sb.append(" 6:").append(getFallbackChannel6());
return super.toString();
}
public int getFallbackChannel1()
{
return getInt(FALLBACK_CHANNEL_ID_1);
}
public int getFallbackChannel2()
{
return getInt(FALLBACK_CHANNEL_ID_2);
}
public int getFallbackChannel3()
{
return getInt(FALLBACK_CHANNEL_ID_3);
}
public int getFallbackChannel4()
{
return getInt(FALLBACK_CHANNEL_ID_4);
}
public int getFallbackChannel5()
{
return getInt(FALLBACK_CHANNEL_ID_5);
}
public int getFallbackChannel6()
{
return getInt(FALLBACK_CHANNEL_ID_6);
}
@Override
public List<Identifier> getIdentifiers()
{
return Collections.emptyList();
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,12 +19,12 @@
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.ExtendedFunction;
import java.util.ArrayList;
import java.util.List;
@@ -33,11 +33,9 @@ import java.util.List;
*/
public class LCExtendedFunctionCommand extends LinkControlWord
{
private static final int[] EXTENDED_FUNCTION = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] EXTENDED_FUNCTION_ARGUMENTS = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] TARGET_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private static final IntField EXTENDED_FUNCTION = IntField.length16(OCTET_1_BIT_8);
private static final IntField EXTENDED_FUNCTION_ARGUMENTS = IntField.length24(OCTET_3_BIT_24);
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mTargetAddress;
private List<Identifier> mIdentifiers;
@@ -47,7 +45,7 @@ public class LCExtendedFunctionCommand extends LinkControlWord
*
* @param message
*/
public LCExtendedFunctionCommand(BinaryMessage message)
public LCExtendedFunctionCommand(CorrectedBinaryMessage message)
{
super(message);
}
@@ -67,7 +65,7 @@ public class LCExtendedFunctionCommand extends LinkControlWord
*/
public ExtendedFunction getExtendedFunction()
{
return ExtendedFunction.fromValue(getMessage().getInt(EXTENDED_FUNCTION));
return ExtendedFunction.fromValue(getInt(EXTENDED_FUNCTION));
}
/**
@@ -75,7 +73,7 @@ public class LCExtendedFunctionCommand extends LinkControlWord
*/
public String getExtendedFunctionArguments()
{
return getMessage().getHex(EXTENDED_FUNCTION_ARGUMENTS, 6);
return getMessage().getHex(EXTENDED_FUNCTION_ARGUMENTS);
}
/**
@@ -85,7 +83,7 @@ public class LCExtendedFunctionCommand extends LinkControlWord
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getMessage().getInt(TARGET_ADDRESS));
mTargetAddress = APCO25RadioIdentifier.createTo(getInt(TARGET_ADDRESS));
}
return mTargetAddress;

View File

@@ -0,0 +1,135 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.radio.FullyQualifiedRadioIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25FullyQualifiedRadioIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.ExtendedSourceLinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.ExtendedFunction;
import java.util.ArrayList;
import java.util.List;
/**
* Extended function command to a target address with an extended SUID
*/
public class LCExtendedFunctionCommandExtended extends ExtendedSourceLinkControlWord
{
private static final IntField EXTENDED_FUNCTION = IntField.length16(OCTET_1_BIT_8);
private static final IntField EXTENDED_FUNCTION_ARGUMENTS = IntField.length24(OCTET_3_BIT_24);
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mTargetAddress;
private FullyQualifiedRadioIdentifier mSourceAddress;
private List<Identifier> mIdentifiers;
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCExtendedFunctionCommandExtended(CorrectedBinaryMessage message)
{
super(message);
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(getMessageStub());
sb.append(" TO:").append(getTargetAddress());
if(hasSourceIDExtension())
{
sb.append(" FM:").append(getSourceAddress());
}
sb.append(" ").append(getExtendedFunction());
sb.append(" ARGUMENTS:").append(getExtendedFunctionArguments());
return sb.toString();
}
/**
* Source address. Doesn't use the parent class method since the source address value is not available.
*/
@Override
public FullyQualifiedRadioIdentifier getSourceAddress()
{
if(mSourceAddress == null && hasSourceIDExtension())
{
int wacn = getSourceIDExtension().getWACN();
int system = getSourceIDExtension().getSystem();
int id = getSourceIDExtension().getId();
mSourceAddress = APCO25FullyQualifiedRadioIdentifier.createFrom(id, wacn, system, id);
}
return mSourceAddress;
}
/**
* Indicates the type of extended function
*/
public ExtendedFunction getExtendedFunction()
{
return ExtendedFunction.fromValue(getInt(EXTENDED_FUNCTION));
}
/**
* Argument(s). May not be required for the class/function and will be set to null (0) if not required.
*/
public String getExtendedFunctionArguments()
{
return getMessage().getHex(EXTENDED_FUNCTION_ARGUMENTS);
}
/**
* Talkgroup address
*/
public Identifier getTargetAddress()
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getInt(TARGET_ADDRESS));
}
return mTargetAddress;
}
/**
* List of identifiers contained in this message
*/
@Override
public List<Identifier> getIdentifiers()
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getTargetAddress());
if(hasSourceIDExtension())
{
mIdentifiers.add(getSourceAddress());
}
}
return mIdentifiers;
}
}

View File

@@ -1,45 +1,39 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
/**
* Current user of an APCO25 channel on both inbound and outbound channels
* Group affiliation query
*/
public class LCGroupAffiliationQuery extends LinkControlWord
{
private static final int[] TARGET_ADDRESS = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47};
private static final int[] SOURCE_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_3_BIT_24);
private static final IntField SOURCE_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mTargetAddress;
private Identifier mSourceAddress;
private List<Identifier> mIdentifiers;
@@ -49,7 +43,7 @@ public class LCGroupAffiliationQuery extends LinkControlWord
*
* @param message
*/
public LCGroupAffiliationQuery(BinaryMessage message)
public LCGroupAffiliationQuery(CorrectedBinaryMessage message)
{
super(message);
}
@@ -70,7 +64,7 @@ public class LCGroupAffiliationQuery extends LinkControlWord
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getMessage().getInt(TARGET_ADDRESS));
mTargetAddress = APCO25RadioIdentifier.createTo(getInt(TARGET_ADDRESS));
}
return mTargetAddress;
@@ -83,7 +77,7 @@ public class LCGroupAffiliationQuery extends LinkControlWord
{
if(mSourceAddress == null)
{
mSourceAddress = APCO25RadioIdentifier.createFrom(getMessage().getInt(SOURCE_ADDRESS));
mSourceAddress = APCO25RadioIdentifier.createFrom(getInt(SOURCE_ADDRESS));
}
return mSourceAddress;

View File

@@ -1,52 +1,49 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel;
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
/**
* Update detailing other users/channels that are active on the network.
* Group voice channel update
*/
public class LCGroupVoiceChannelUpdate extends LinkControlWord implements IFrequencyBandReceiver
{
public static final int[] FREQUENCY_BAND_A = {8, 9, 10, 11};
public static final int[] CHANNEL_A = {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
public static final int[] GROUP_ADDRESS_A = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
public static final int[] FREQUENCY_BAND_B = {40, 41, 42, 43};
public static final int[] CHANNEL_B = {44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55};
public static final int[] GROUP_ADDRESS_B = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
private static final IntField FREQUENCY_BAND_A = IntField.length4(OCTET_1_BIT_8);
private static final IntField CHANNEL_A = IntField.length12(OCTET_1_BIT_8 + 4);
private static final IntField GROUP_ADDRESS_A = IntField.length16(OCTET_3_BIT_24);
private static final IntField FREQUENCY_BAND_B = IntField.length4(OCTET_5_BIT_40);
private static final IntField CHANNEL_B = IntField.length12(OCTET_5_BIT_40 + 4);
private static final IntField GROUP_ADDRESS_B = IntField.length16(OCTET_7_BIT_56);
private IChannelDescriptor mChannelA;
private IChannelDescriptor mChannelB;
private APCO25Channel mChannelA;
private APCO25Channel mChannelB;
private Identifier mTalkgroupA;
private Identifier mTalkgroupB;
private List<Identifier> mIdentifiers;
@@ -54,7 +51,7 @@ public class LCGroupVoiceChannelUpdate extends LinkControlWord implements IFrequ
/**
* Constructs a Link Control Word from the binary message sequence.
*/
public LCGroupVoiceChannelUpdate(BinaryMessage message)
public LCGroupVoiceChannelUpdate(CorrectedBinaryMessage message)
{
super(message);
}
@@ -92,21 +89,21 @@ public class LCGroupVoiceChannelUpdate extends LinkControlWord implements IFrequ
return mIdentifiers;
}
public IChannelDescriptor getChannelA()
public APCO25Channel getChannelA()
{
if(mChannelA == null)
{
mChannelA = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND_A), getMessage().getInt(CHANNEL_A));
mChannelA = APCO25Channel.create(getInt(FREQUENCY_BAND_A), getInt(CHANNEL_A));
}
return mChannelA;
}
public IChannelDescriptor getChannelB()
public APCO25Channel getChannelB()
{
if(mChannelB == null)
{
mChannelB = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND_B), getMessage().getInt(CHANNEL_B));
mChannelB = APCO25Channel.create(getInt(FREQUENCY_BAND_B), getInt(CHANNEL_B));
}
return mChannelB;
@@ -114,14 +111,14 @@ public class LCGroupVoiceChannelUpdate extends LinkControlWord implements IFrequ
public boolean hasChannelB()
{
return getMessage().getInt(CHANNEL_B) != 0 && getMessage().getInt(GROUP_ADDRESS_A) != getMessage().getInt(GROUP_ADDRESS_B);
return getInt(CHANNEL_B) != 0 && getInt(GROUP_ADDRESS_A) != getInt(GROUP_ADDRESS_B);
}
public Identifier getGroupAddressA()
{
if(mTalkgroupA == null)
{
mTalkgroupA = APCO25Talkgroup.create(getMessage().getInt(GROUP_ADDRESS_A));
mTalkgroupA = APCO25Talkgroup.create(getInt(GROUP_ADDRESS_A));
}
return mTalkgroupA;
@@ -131,7 +128,7 @@ public class LCGroupVoiceChannelUpdate extends LinkControlWord implements IFrequ
{
if(mTalkgroupB == null)
{
mTalkgroupB = APCO25Talkgroup.create(getMessage().getInt(GROUP_ADDRESS_B));
mTalkgroupB = APCO25Talkgroup.create(getInt(GROUP_ADDRESS_B));
}
return mTalkgroupB;

View File

@@ -1,61 +1,55 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel;
import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel;
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.VoiceLinkControlMessage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Update detailing other users/channels that are active on the network.
* Group voice channel update explicit
*/
public class LCGroupVoiceChannelUpdateExplicit extends LinkControlWord implements IFrequencyBandReceiver
public class LCGroupVoiceChannelUpdateExplicit extends VoiceLinkControlMessage implements IFrequencyBandReceiver
{
public static final int[] SERVICE_OPTIONS = {16, 17, 18, 19, 20, 21, 22, 23};
public static final int[] GROUP_ADDRESS = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
public static final int[] DOWNLINK_FREQUENCY_BAND = {40, 41, 42, 43};
public static final int[] DOWNLINK_CHANNEL = {44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55};
public static final int[] UPLINK_FREQUENCY_BAND = {56, 57, 58, 59};
public static final int[] UPLINK_CHANNEL = {60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
private VoiceServiceOptions mVoiceServiceOptions;
private IChannelDescriptor mChannel;
private List<IChannelDescriptor> mChannels;
private static final IntField GROUP_ADDRESS = IntField.length16(OCTET_3_BIT_24);
private static final IntField DOWNLINK_FREQUENCY_BAND = IntField.length4(OCTET_5_BIT_40);
private static final IntField DOWNLINK_CHANNEL = IntField.length12(OCTET_5_BIT_40 + 4);
private static final IntField UPLINK_FREQUENCY_BAND = IntField.length4(OCTET_7_BIT_56);
private static final IntField UPLINK_CHANNEL = IntField.length12(OCTET_7_BIT_56 + 4);
private APCO25Channel mChannel;
private Identifier mTalkgroup;
private List<Identifier> mIdentifiers;
/**
* Constructs a Link Control Word from the binary message sequence.
*/
public LCGroupVoiceChannelUpdateExplicit(BinaryMessage message)
public LCGroupVoiceChannelUpdateExplicit(CorrectedBinaryMessage message)
{
super(message);
}
@@ -66,24 +60,11 @@ public class LCGroupVoiceChannelUpdateExplicit extends LinkControlWord implement
sb.append(getMessageStub());
sb.append(" TALKGROUP:").append(getGroupAddress());
sb.append(" ").append(getChannel());
sb.append(" ").append(getVoiceServiceOptions());
sb.append(" ").append(getServiceOptions());
return sb.toString();
}
/**
* Service options for this channel
*/
public VoiceServiceOptions getVoiceServiceOptions()
{
if(mVoiceServiceOptions == null)
{
mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS));
}
return mVoiceServiceOptions;
}
@Override
public List<Identifier> getIdentifiers()
{
@@ -96,13 +77,12 @@ public class LCGroupVoiceChannelUpdateExplicit extends LinkControlWord implement
return mIdentifiers;
}
public IChannelDescriptor getChannel()
public APCO25Channel getChannel()
{
if(mChannel == null)
{
mChannel = APCO25ExplicitChannel.create(getMessage().getInt(DOWNLINK_FREQUENCY_BAND),
getMessage().getInt(DOWNLINK_CHANNEL), getMessage().getInt(UPLINK_FREQUENCY_BAND),
getMessage().getInt(UPLINK_CHANNEL));
mChannel = APCO25ExplicitChannel.create(getInt(DOWNLINK_FREQUENCY_BAND), getInt(DOWNLINK_CHANNEL),
getInt(UPLINK_FREQUENCY_BAND), getInt(UPLINK_CHANNEL));
}
return mChannel;
@@ -112,7 +92,7 @@ public class LCGroupVoiceChannelUpdateExplicit extends LinkControlWord implement
{
if(mTalkgroup == null)
{
mTalkgroup = APCO25Talkgroup.create(getMessage().getInt(GROUP_ADDRESS));
mTalkgroup = APCO25Talkgroup.create(getInt(GROUP_ADDRESS));
}
return mTalkgroup;
@@ -121,8 +101,6 @@ public class LCGroupVoiceChannelUpdateExplicit extends LinkControlWord implement
@Override
public List<IChannelDescriptor> getChannels()
{
List<IChannelDescriptor> channels = new ArrayList<>();
channels.add(getChannel());
return channels;
return Collections.singletonList(getChannel());
}
}

View File

@@ -1,48 +1,40 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
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.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.VoiceLinkControlMessage;
import java.util.ArrayList;
import java.util.List;
/**
* Current user of an APCO25 channel on both inbound and outbound channels
* Group voice channel user.
*/
public class LCGroupVoiceChannelUser extends LinkControlWord
public class LCGroupVoiceChannelUser extends VoiceLinkControlMessage
{
private static final int[] SERVICE_OPTIONS = {16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] GROUP_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] SOURCE_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private VoiceServiceOptions mVoiceServiceOptions;
private static final IntField GROUP_ADDRESS = IntField.length16(OCTET_4_BIT_32);
private static final IntField SOURCE_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mGroupAddress;
private Identifier mSourceAddress;
private List<Identifier> mIdentifiers;
@@ -52,7 +44,7 @@ public class LCGroupVoiceChannelUser extends LinkControlWord
*
* @param message
*/
public LCGroupVoiceChannelUser(BinaryMessage message)
public LCGroupVoiceChannelUser(CorrectedBinaryMessage message)
{
super(message);
}
@@ -63,23 +55,10 @@ public class LCGroupVoiceChannelUser extends LinkControlWord
sb.append(getMessageStub());
sb.append(" FM:").append(getSourceAddress());
sb.append(" TO:").append(getGroupAddress());
sb.append(" SERVICE OPTIONS:").append(getVoiceServiceOptions());
sb.append(" SERVICE OPTIONS:").append(getServiceOptions());
return sb.toString();
}
/**
* Service Options for this channel
*/
public VoiceServiceOptions getVoiceServiceOptions()
{
if(mVoiceServiceOptions == null)
{
mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS));
}
return mVoiceServiceOptions;
}
/**
* Talkgroup address
*/
@@ -87,7 +66,7 @@ public class LCGroupVoiceChannelUser extends LinkControlWord
{
if(mGroupAddress == null)
{
mGroupAddress = APCO25Talkgroup.create(getMessage().getInt(GROUP_ADDRESS));
mGroupAddress = APCO25Talkgroup.create(getInt(GROUP_ADDRESS));
}
return mGroupAddress;
@@ -100,12 +79,20 @@ public class LCGroupVoiceChannelUser extends LinkControlWord
{
if(mSourceAddress == null)
{
mSourceAddress = APCO25RadioIdentifier.createFrom(getMessage().getInt(SOURCE_ADDRESS));
mSourceAddress = APCO25RadioIdentifier.createFrom(getInt(SOURCE_ADDRESS));
}
return mSourceAddress;
}
/**
* Indicates if the source address is valid and non-zero
*/
public boolean hasSourceAddress()
{
return getInt(SOURCE_ADDRESS) > 0;
}
/**
* List of identifiers contained in this message
*/
@@ -116,7 +103,10 @@ public class LCGroupVoiceChannelUser extends LinkControlWord
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getGroupAddress());
mIdentifiers.add(getSourceAddress());
if(hasSourceAddress())
{
mIdentifiers.add(getSourceAddress());
}
}
return mIdentifiers;

View File

@@ -1,46 +1,41 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.message.APCO25ShortDataMessage;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
/**
* Echo of the status update from a subscriber when the destination of the update is another subscriber unit.
* Echo of the short data message from a subscriber when the destination of the update is another subscriber unit.
*/
public class LCMessageUpdate extends LinkControlWord
{
private static final int[] MESSAGE = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] TARGET_ADDRESS = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47};
private static final int[] SOURCE_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private static final IntField MESSAGE = IntField.length16(OCTET_1_BIT_8);
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_3_BIT_24);
private static final IntField SOURCE_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mShortDataMessage;
private Identifier mTargetAddress;
@@ -52,7 +47,7 @@ public class LCMessageUpdate extends LinkControlWord
*
* @param message
*/
public LCMessageUpdate(BinaryMessage message)
public LCMessageUpdate(CorrectedBinaryMessage message)
{
super(message);
}
@@ -71,7 +66,7 @@ public class LCMessageUpdate extends LinkControlWord
{
if(mShortDataMessage == null)
{
mShortDataMessage = APCO25ShortDataMessage.create(getMessage().getInt(MESSAGE));
mShortDataMessage = APCO25ShortDataMessage.create(getInt(MESSAGE));
}
return mShortDataMessage;
@@ -84,7 +79,7 @@ public class LCMessageUpdate extends LinkControlWord
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getMessage().getInt(TARGET_ADDRESS));
mTargetAddress = APCO25RadioIdentifier.createTo(getInt(TARGET_ADDRESS));
}
return mTargetAddress;
@@ -97,7 +92,7 @@ public class LCMessageUpdate extends LinkControlWord
{
if(mSourceAddress == null)
{
mSourceAddress = APCO25RadioIdentifier.createFrom(getMessage().getInt(SOURCE_ADDRESS));
mSourceAddress = APCO25RadioIdentifier.createFrom(getInt(SOURCE_ADDRESS));
}
return mSourceAddress;

View File

@@ -0,0 +1,108 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.message.APCO25ShortDataMessage;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.ExtendedSourceLinkControlWord;
import java.util.ArrayList;
import java.util.List;
/**
* Message Update with extended SUID
*/
public class LCMessageUpdateExtended extends ExtendedSourceLinkControlWord
{
private static final IntField MESSAGE = IntField.length16(OCTET_1_BIT_8);
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_3_BIT_24);
private Identifier mShortDataMessage;
private Identifier mTargetAddress;
private List<Identifier> mIdentifiers;
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCMessageUpdateExtended(CorrectedBinaryMessage message)
{
super(message);
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(getMessageStub());
sb.append(" TO:").append(getTargetAddress());
if(hasSourceIDExtension())
{
sb.append(" FM:").append(getSourceAddress());
}
sb.append(" SDM:").append(getShortDataMessage());
return sb.toString();
}
public Identifier getShortDataMessage()
{
if(mShortDataMessage == null)
{
mShortDataMessage = APCO25ShortDataMessage.create(getInt(MESSAGE));
}
return mShortDataMessage;
}
/**
* Talkgroup address
*/
public Identifier getTargetAddress()
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getInt(TARGET_ADDRESS));
}
return mTargetAddress;
}
/**
* List of identifiers contained in this message
*/
@Override
public List<Identifier> getIdentifiers()
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getTargetAddress());
if(hasSourceIDExtension())
{
mIdentifiers.add(getSourceAddress());
}
mIdentifiers.add(getShortDataMessage());
}
return mIdentifiers;
}
}

View File

@@ -1,28 +1,26 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.APCO25System;
@@ -31,7 +29,6 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass;
import java.util.ArrayList;
import java.util.List;
@@ -40,12 +37,11 @@ import java.util.List;
*/
public class LCNetworkStatusBroadcast extends LinkControlWord implements IFrequencyBandReceiver
{
private static final int[] RESERVED = {8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] WACN = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35};
private static final int[] SYSTEM = {36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] FREQUENCY_BAND = {48, 49, 50, 51};
private static final int[] CHANNEL_NUMBER = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
private static final int[] SERVICE_CLASS = {64, 65, 66, 67, 68, 69, 70, 71};
private static final IntField WACN = IntField.length20(OCTET_2_BIT_16);
private static final IntField SYSTEM = IntField.length12(OCTET_4_BIT_32 + 4);
private static final IntField FREQUENCY_BAND = IntField.length4(OCTET_6_BIT_48);
private static final IntField CHANNEL_NUMBER = IntField.length12(OCTET_6_BIT_48 + 4);
private static final IntField SERVICE_CLASS = IntField.length8(OCTET_8_BIT_64);
private List<Identifier> mIdentifiers;
private Identifier mWACN;
@@ -58,7 +54,7 @@ public class LCNetworkStatusBroadcast extends LinkControlWord implements IFreque
*
* @param message
*/
public LCNetworkStatusBroadcast(BinaryMessage message)
public LCNetworkStatusBroadcast(CorrectedBinaryMessage message)
{
super(message);
}
@@ -78,7 +74,7 @@ public class LCNetworkStatusBroadcast extends LinkControlWord implements IFreque
{
if(mWACN == null)
{
mWACN = APCO25Wacn.create(getMessage().getInt(WACN));
mWACN = APCO25Wacn.create(getInt(WACN));
}
return mWACN;
@@ -88,7 +84,7 @@ public class LCNetworkStatusBroadcast extends LinkControlWord implements IFreque
{
if(mSystem == null)
{
mSystem = APCO25System.create(getMessage().getInt(SYSTEM));
mSystem = APCO25System.create(getInt(SYSTEM));
}
return mSystem;
@@ -98,8 +94,7 @@ public class LCNetworkStatusBroadcast extends LinkControlWord implements IFreque
{
if(mChannel == null)
{
mChannel = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND),
getMessage().getInt(CHANNEL_NUMBER));
mChannel = APCO25Channel.create(getInt(FREQUENCY_BAND), getInt(CHANNEL_NUMBER));
}
return mChannel;
@@ -109,7 +104,7 @@ public class LCNetworkStatusBroadcast extends LinkControlWord implements IFreque
{
if(mSystemServiceClass == null)
{
mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS));
mSystemServiceClass = new SystemServiceClass(getInt(SERVICE_CLASS));
}
return mSystemServiceClass;

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,12 +14,13 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.APCO25System;
@@ -28,22 +28,21 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25Wacn;
import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Secondary control channel broadcast information.
* Network status broadcast explicit
*/
public class LCNetworkStatusBroadcastExplicit extends LinkControlWord implements IFrequencyBandReceiver
{
private static final int[] WACN = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27};
private static final int[] SYSTEM = {28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] DOWNLINK_FREQUENCY_BAND = {40, 41, 42, 43};
private static final int[] DOWNLINK_CHANNEL_NUMBER = {44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55};
private static final int[] UPLINK_FREQUENCY_BAND = {56, 57, 58, 59};
private static final int[] UPLINK_CHANNEL_NUMBER = {60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
private static final IntField WACN = IntField.length20(OCTET_1_BIT_8);
private static final IntField SYSTEM = IntField.length12(OCTET_3_BIT_24 + 4);
private static final IntField DOWNLINK_FREQUENCY_BAND = IntField.length4(OCTET_5_BIT_40);
private static final IntField DOWNLINK_CHANNEL_NUMBER = IntField.length12(OCTET_5_BIT_40 + 4);
private static final IntField UPLINK_FREQUENCY_BAND = IntField.length4(OCTET_7_BIT_56);
private static final IntField UPLINK_CHANNEL_NUMBER = IntField.length12(OCTET_7_BIT_56 + 4);
private List<Identifier> mIdentifiers;
private Identifier mWACN;
private Identifier mSystem;
@@ -54,7 +53,7 @@ public class LCNetworkStatusBroadcastExplicit extends LinkControlWord implements
*
* @param message
*/
public LCNetworkStatusBroadcastExplicit(BinaryMessage message)
public LCNetworkStatusBroadcastExplicit(CorrectedBinaryMessage message)
{
super(message);
}
@@ -73,7 +72,7 @@ public class LCNetworkStatusBroadcastExplicit extends LinkControlWord implements
{
if(mWACN == null)
{
mWACN = APCO25Wacn.create(getMessage().getInt(WACN));
mWACN = APCO25Wacn.create(getInt(WACN));
}
return mWACN;
@@ -83,7 +82,7 @@ public class LCNetworkStatusBroadcastExplicit extends LinkControlWord implements
{
if(mSystem == null)
{
mSystem = APCO25System.create(getMessage().getInt(SYSTEM));
mSystem = APCO25System.create(getInt(SYSTEM));
}
return mSystem;
@@ -93,9 +92,8 @@ public class LCNetworkStatusBroadcastExplicit extends LinkControlWord implements
{
if(mChannel == null)
{
mChannel = APCO25ExplicitChannel.create(getMessage().getInt(DOWNLINK_FREQUENCY_BAND),
getMessage().getInt(DOWNLINK_CHANNEL_NUMBER), getMessage().getInt(UPLINK_FREQUENCY_BAND),
getMessage().getInt(UPLINK_CHANNEL_NUMBER));
mChannel = APCO25ExplicitChannel.create(getInt(DOWNLINK_FREQUENCY_BAND), getInt(DOWNLINK_CHANNEL_NUMBER),
getInt(UPLINK_FREQUENCY_BAND), getInt(UPLINK_CHANNEL_NUMBER));
}
return mChannel;
@@ -120,8 +118,6 @@ public class LCNetworkStatusBroadcastExplicit extends LinkControlWord implements
@Override
public List<IChannelDescriptor> getChannels()
{
List<IChannelDescriptor> channels = new ArrayList<>();
channels.add(getChannel());
return channels;
return Collections.singletonList(getChannel());
}
}

View File

@@ -1,48 +1,44 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.encryption.APCO25EncryptionKey;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
/**
* Echo of the status update from a subscriber when the destination of the update is another subscriber unit.
* Protection (ie encryption) parameter broadcast.
*
* Note: this is an obsolete message.
*/
public class LCProtectionParameterBroadcast extends LinkControlWord
{
private static final int[] RESERVED = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] ALGORITHM_ID = {24, 25, 26, 27, 28, 29, 30, 31};
private static final int[] KEY_ID = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] TARGET_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private static final IntField ALGORITHM_ID = IntField.length8(OCTET_3_BIT_24);
private static final IntField KEY_ID = IntField.length16(OCTET_4_BIT_32);
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mEncryptionKey;
private Identifier mTargetAddress;
private List<Identifier> mIdentifiers;
@@ -52,7 +48,7 @@ public class LCProtectionParameterBroadcast extends LinkControlWord
*
* @param message
*/
public LCProtectionParameterBroadcast(BinaryMessage message)
public LCProtectionParameterBroadcast(CorrectedBinaryMessage message)
{
super(message);
}
@@ -70,8 +66,8 @@ public class LCProtectionParameterBroadcast extends LinkControlWord
{
if(mEncryptionKey == null)
{
mEncryptionKey = EncryptionKeyIdentifier.create(APCO25EncryptionKey.create(getMessage().getInt(ALGORITHM_ID),
getMessage().getInt(KEY_ID)));
mEncryptionKey = EncryptionKeyIdentifier.create(APCO25EncryptionKey.create(getInt(ALGORITHM_ID),
getInt(KEY_ID)));
}
return mEncryptionKey;
@@ -84,7 +80,7 @@ public class LCProtectionParameterBroadcast extends LinkControlWord
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getMessage().getInt(TARGET_ADDRESS));
mTargetAddress = APCO25RadioIdentifier.createTo(getInt(TARGET_ADDRESS));
}
return mTargetAddress;

View File

@@ -1,28 +1,26 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra;
@@ -33,7 +31,6 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass;
import java.util.ArrayList;
import java.util.List;
@@ -42,13 +39,13 @@ import java.util.List;
*/
public class LCRFSSStatusBroadcast extends LinkControlWord implements IFrequencyBandReceiver
{
private static final int[] LRA = {8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] SYSTEM = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
private static final int[] RFSS = {32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] SITE = {40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] FREQUENCY_BAND = {48, 49, 50, 51};
private static final int[] CHANNEL_NUMBER = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
private static final int[] SERVICE_CLASS = {64, 65, 66, 67, 68, 69, 70, 71};
private static final IntField LRA = IntField.length8(OCTET_1_BIT_8);
private static final IntField SYSTEM = IntField.length12(OCTET_2_BIT_16 + 4);
private static final IntField RFSS = IntField.length8(OCTET_4_BIT_32);
private static final IntField SITE = IntField.length8(OCTET_5_BIT_40);
private static final IntField FREQUENCY_BAND = IntField.length4(OCTET_6_BIT_48);
private static final IntField CHANNEL_NUMBER = IntField.length12(OCTET_6_BIT_48 + 4);
private static final IntField SERVICE_CLASS = IntField.length8(OCTET_8_BIT_64);
private List<Identifier> mIdentifiers;
private Identifier mLRA;
@@ -63,7 +60,7 @@ public class LCRFSSStatusBroadcast extends LinkControlWord implements IFrequency
*
* @param message
*/
public LCRFSSStatusBroadcast(BinaryMessage message)
public LCRFSSStatusBroadcast(CorrectedBinaryMessage message)
{
super(message);
}
@@ -84,7 +81,7 @@ public class LCRFSSStatusBroadcast extends LinkControlWord implements IFrequency
{
if(mLRA == null)
{
mLRA = APCO25Lra.create(getMessage().getInt(LRA));
mLRA = APCO25Lra.create(getInt(LRA));
}
return mLRA;
@@ -94,7 +91,7 @@ public class LCRFSSStatusBroadcast extends LinkControlWord implements IFrequency
{
if(mSystem == null)
{
mSystem = APCO25System.create(getMessage().getInt(SYSTEM));
mSystem = APCO25System.create(getInt(SYSTEM));
}
return mSystem;
@@ -104,7 +101,7 @@ public class LCRFSSStatusBroadcast extends LinkControlWord implements IFrequency
{
if(mRFSS == null)
{
mRFSS = APCO25Rfss.create(getMessage().getInt(RFSS));
mRFSS = APCO25Rfss.create(getInt(RFSS));
}
return mRFSS;
@@ -114,7 +111,7 @@ public class LCRFSSStatusBroadcast extends LinkControlWord implements IFrequency
{
if(mSite == null)
{
mSite = APCO25Site.create(getMessage().getInt(SITE));
mSite = APCO25Site.create(getInt(SITE));
}
return mSite;
@@ -124,8 +121,7 @@ public class LCRFSSStatusBroadcast extends LinkControlWord implements IFrequency
{
if(mChannel == null)
{
mChannel = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND),
getMessage().getInt(CHANNEL_NUMBER));
mChannel = APCO25Channel.create(getInt(FREQUENCY_BAND), getInt(CHANNEL_NUMBER));
}
return mChannel;
@@ -135,7 +131,7 @@ public class LCRFSSStatusBroadcast extends LinkControlWord implements IFrequency
{
if(mSystemServiceClass == null)
{
mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS));
mSystemServiceClass = new SystemServiceClass(getInt(SERVICE_CLASS));
}
return mSystemServiceClass;

View File

@@ -1,28 +1,26 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra;
@@ -32,24 +30,23 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitCha
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Secondary control channel broadcast information.
* RFSS Status Broadcast Explicit
*/
public class LCRFSSStatusBroadcastExplicit extends LinkControlWord implements IFrequencyBandReceiver
{
private static final int[] LRA = {8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] UPLINK_FREQUENCY_BAND = {16, 17, 18, 19};
private static final int[] UPLINK_CHANNEL_NUMBER = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
private static final int[] RFSS = {32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] SITE = {40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] DOWNLINK_FREQUENCY_BAND = {48, 49, 50, 51};
private static final int[] DOWNLINK_CHANNEL_NUMBER = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
private static final int[] SERVICE_CLASS = {64, 65, 66, 67, 68, 69, 70, 71};
private static final IntField LRA = IntField.length8(OCTET_1_BIT_8);
private static final IntField UPLINK_FREQUENCY_BAND = IntField.length4(OCTET_2_BIT_16);
private static final IntField UPLINK_CHANNEL_NUMBER = IntField.length12(OCTET_2_BIT_16 + 4);
private static final IntField RFSS = IntField.length8(OCTET_4_BIT_32);
private static final IntField SITE = IntField.length8(OCTET_5_BIT_40);
private static final IntField DOWNLINK_FREQUENCY_BAND = IntField.length4(OCTET_6_BIT_48);
private static final IntField DOWNLINK_CHANNEL_NUMBER = IntField.length12(OCTET_6_BIT_48 + 4);
private static final IntField SERVICE_CLASS = IntField.length8(OCTET_8_BIT_64);
private List<Identifier> mIdentifiers;
private Identifier mLRA;
private Identifier mRFSS;
@@ -62,7 +59,7 @@ public class LCRFSSStatusBroadcastExplicit extends LinkControlWord implements IF
*
* @param message
*/
public LCRFSSStatusBroadcastExplicit(BinaryMessage message)
public LCRFSSStatusBroadcastExplicit(CorrectedBinaryMessage message)
{
super(message);
}
@@ -82,7 +79,7 @@ public class LCRFSSStatusBroadcastExplicit extends LinkControlWord implements IF
{
if(mLRA == null)
{
mLRA = APCO25Lra.create(getMessage().getInt(LRA));
mLRA = APCO25Lra.create(getInt(LRA));
}
return mLRA;
@@ -92,7 +89,7 @@ public class LCRFSSStatusBroadcastExplicit extends LinkControlWord implements IF
{
if(mRFSS == null)
{
mRFSS = APCO25Rfss.create(getMessage().getInt(RFSS));
mRFSS = APCO25Rfss.create(getInt(RFSS));
}
return mRFSS;
@@ -102,7 +99,7 @@ public class LCRFSSStatusBroadcastExplicit extends LinkControlWord implements IF
{
if(mSite == null)
{
mSite = APCO25Site.create(getMessage().getInt(SITE));
mSite = APCO25Site.create(getInt(SITE));
}
return mSite;
@@ -112,9 +109,8 @@ public class LCRFSSStatusBroadcastExplicit extends LinkControlWord implements IF
{
if(mChannel == null)
{
mChannel = APCO25ExplicitChannel.create(getMessage().getInt(DOWNLINK_FREQUENCY_BAND),
getMessage().getInt(DOWNLINK_CHANNEL_NUMBER), getMessage().getInt(UPLINK_FREQUENCY_BAND),
getMessage().getInt(UPLINK_CHANNEL_NUMBER));
mChannel = APCO25ExplicitChannel.create(getInt(DOWNLINK_FREQUENCY_BAND), getInt(DOWNLINK_CHANNEL_NUMBER),
getInt(UPLINK_FREQUENCY_BAND), getInt(UPLINK_CHANNEL_NUMBER));
}
return mChannel;
@@ -124,7 +120,7 @@ public class LCRFSSStatusBroadcastExplicit extends LinkControlWord implements IF
{
if(mSystemServiceClass == null)
{
mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS));
mSystemServiceClass = new SystemServiceClass(getInt(SERVICE_CLASS));
}
return mSystemServiceClass;
@@ -150,8 +146,6 @@ public class LCRFSSStatusBroadcastExplicit extends LinkControlWord implements IF
@Override
public List<IChannelDescriptor> getChannels()
{
List<IChannelDescriptor> channels = new ArrayList<>();
channels.add(getChannel());
return channels;
return Collections.singletonList(getChannel());
}
}

View File

@@ -1,28 +1,26 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss;
@@ -31,23 +29,22 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel;
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass;
import java.util.ArrayList;
import java.util.List;
/**
* Secondary control channel broadcast information.
* Secondary control channel broadcast.
*/
public class LCSecondaryControlChannelBroadcast extends LinkControlWord implements IFrequencyBandReceiver
{
private static final int[] RFSS = {8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] SITE = {16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] FREQUENCY_BAND_A = {24, 25, 26, 27};
private static final int[] CHANNEL_NUMBER_A = {28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] SERVICE_CLASS_A = {40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] FREQUENCY_BAND_B = {48, 49, 50, 51};
private static final int[] CHANNEL_NUMBER_B = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
private static final int[] SERVICE_CLASS_B = {64, 65, 66, 67, 68, 69, 70, 71};
private static final IntField RFSS = IntField.length8(OCTET_1_BIT_8);
private static final IntField SITE = IntField.length8(OCTET_2_BIT_16);
private static final IntField FREQUENCY_BAND_A = IntField.length4(OCTET_3_BIT_24);
private static final IntField CHANNEL_NUMBER_A = IntField.length12(OCTET_3_BIT_24 + 4);
private static final IntField SERVICE_CLASS_A = IntField.length8(OCTET_5_BIT_40);
private static final IntField FREQUENCY_BAND_B = IntField.length4(OCTET_6_BIT_48);
private static final IntField CHANNEL_NUMBER_B = IntField.length12(OCTET_6_BIT_48 + 4);
private static final IntField SERVICE_CLASS_B = IntField.length8(OCTET_8_BIT_64);
private List<Identifier> mIdentifiers;
private Identifier mRFSS;
@@ -62,7 +59,7 @@ public class LCSecondaryControlChannelBroadcast extends LinkControlWord implemen
*
* @param message
*/
public LCSecondaryControlChannelBroadcast(BinaryMessage message)
public LCSecondaryControlChannelBroadcast(CorrectedBinaryMessage message)
{
super(message);
}
@@ -87,7 +84,7 @@ public class LCSecondaryControlChannelBroadcast extends LinkControlWord implemen
{
if(mRFSS == null)
{
mRFSS = APCO25Rfss.create(getMessage().getInt(RFSS));
mRFSS = APCO25Rfss.create(getInt(RFSS));
}
return mRFSS;
@@ -97,7 +94,7 @@ public class LCSecondaryControlChannelBroadcast extends LinkControlWord implemen
{
if(mSite == null)
{
mSite = APCO25Site.create(getMessage().getInt(SITE));
mSite = APCO25Site.create(getInt(SITE));
}
return mSite;
@@ -107,8 +104,7 @@ public class LCSecondaryControlChannelBroadcast extends LinkControlWord implemen
{
if(mChannelA == null)
{
mChannelA = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND_A),
getMessage().getInt(CHANNEL_NUMBER_A));
mChannelA = APCO25Channel.create(getInt(FREQUENCY_BAND_A), getInt(CHANNEL_NUMBER_A));
}
return mChannelA;
@@ -116,16 +112,14 @@ public class LCSecondaryControlChannelBroadcast extends LinkControlWord implemen
private boolean hasChannelB()
{
return getMessage().getInt(CHANNEL_NUMBER_A) != getMessage().getInt(CHANNEL_NUMBER_B) &&
getMessage().getInt(SERVICE_CLASS_B) != 0;
return getInt(CHANNEL_NUMBER_A) != getInt(CHANNEL_NUMBER_B) && getInt(SERVICE_CLASS_B) != 0;
}
public IChannelDescriptor getChannelB()
{
if(mChannelB == null)
{
mChannelB = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND_B),
getMessage().getInt(CHANNEL_NUMBER_B));
mChannelB = APCO25Channel.create(getInt(FREQUENCY_BAND_B), getInt(CHANNEL_NUMBER_B));
}
return mChannelB;
@@ -135,7 +129,7 @@ public class LCSecondaryControlChannelBroadcast extends LinkControlWord implemen
{
if(mSystemServiceClassA == null)
{
mSystemServiceClassA = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS_A));
mSystemServiceClassA = new SystemServiceClass(getInt(SERVICE_CLASS_A));
}
return mSystemServiceClassA;
@@ -146,7 +140,7 @@ public class LCSecondaryControlChannelBroadcast extends LinkControlWord implemen
{
if(mSystemServiceClassB == null)
{
mSystemServiceClassB = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS_B));
mSystemServiceClassB = new SystemServiceClass(getInt(SERVICE_CLASS_B));
}
return mSystemServiceClassB;

View File

@@ -1,28 +1,26 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss;
@@ -31,8 +29,8 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitCha
import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -40,15 +38,13 @@ import java.util.List;
*/
public class LCSecondaryControlChannelBroadcastExplicit extends LinkControlWord implements IFrequencyBandReceiver
{
private static final int[] RFSS = {8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] SITE = {16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] DOWNLINK_FREQUENCY_BAND = {24, 25, 26, 27};
private static final int[] DOWNLINK_CHANNEL_NUMBER = {28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] UPLINK_FREQUENCY_BAND = {40, 41, 42, 43};
private static final int[] UPNLINK_CHANNEL_NUMBER = {44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55};
private static final int[] SERVICE_CLASS = {56, 57, 58, 59, 60, 61, 62, 63};
private static final int[] RESERVED = {64, 65, 66, 67, 68, 69, 70, 71};
private static final IntField RFSS = IntField.length8(OCTET_1_BIT_8);
private static final IntField SITE = IntField.length8(OCTET_2_BIT_16);
private static final IntField DOWNLINK_FREQUENCY_BAND = IntField.length4(OCTET_3_BIT_24);
private static final IntField DOWNLINK_CHANNEL_NUMBER = IntField.length12(OCTET_3_BIT_24 + 4);
private static final IntField UPLINK_FREQUENCY_BAND = IntField.length4(OCTET_5_BIT_40);
private static final IntField UPNLINK_CHANNEL_NUMBER = IntField.length12(OCTET_5_BIT_40 + 4);
private static final IntField SERVICE_CLASS = IntField.length8(OCTET_7_BIT_56);
private List<Identifier> mIdentifiers;
private Identifier mRFSS;
private Identifier mSite;
@@ -60,7 +56,7 @@ public class LCSecondaryControlChannelBroadcastExplicit extends LinkControlWord
*
* @param message
*/
public LCSecondaryControlChannelBroadcastExplicit(BinaryMessage message)
public LCSecondaryControlChannelBroadcastExplicit(CorrectedBinaryMessage message)
{
super(message);
}
@@ -79,7 +75,7 @@ public class LCSecondaryControlChannelBroadcastExplicit extends LinkControlWord
{
if(mRFSS == null)
{
mRFSS = APCO25Rfss.create(getMessage().getInt(RFSS));
mRFSS = APCO25Rfss.create(getInt(RFSS));
}
return mRFSS;
@@ -89,7 +85,7 @@ public class LCSecondaryControlChannelBroadcastExplicit extends LinkControlWord
{
if(mSite == null)
{
mSite = APCO25Site.create(getMessage().getInt(SITE));
mSite = APCO25Site.create(getInt(SITE));
}
return mSite;
@@ -99,9 +95,8 @@ public class LCSecondaryControlChannelBroadcastExplicit extends LinkControlWord
{
if(mChannel == null)
{
mChannel = APCO25ExplicitChannel.create(getMessage().getInt(DOWNLINK_FREQUENCY_BAND),
getMessage().getInt(DOWNLINK_CHANNEL_NUMBER), getMessage().getInt(UPLINK_FREQUENCY_BAND),
getMessage().getInt(UPNLINK_CHANNEL_NUMBER));
mChannel = APCO25ExplicitChannel.create(getInt(DOWNLINK_FREQUENCY_BAND), getInt(DOWNLINK_CHANNEL_NUMBER),
getInt(UPLINK_FREQUENCY_BAND), getInt(UPNLINK_CHANNEL_NUMBER));
}
return mChannel;
@@ -111,7 +106,7 @@ public class LCSecondaryControlChannelBroadcastExplicit extends LinkControlWord
{
if(mSystemServiceClass == null)
{
mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS));
mSystemServiceClass = new SystemServiceClass(getInt(SERVICE_CLASS));
}
return mSystemServiceClass;
@@ -136,8 +131,6 @@ public class LCSecondaryControlChannelBroadcastExplicit extends LinkControlWord
@Override
public List<IChannelDescriptor> getChannels()
{
List<IChannelDescriptor> channels = new ArrayList<>();
channels.add(getChannel());
return channels;
return Collections.singletonList(getChannel());
}
}

View File

@@ -0,0 +1,89 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.Collections;
import java.util.List;
/**
* Source ID extension word. This is used in conjunction with another link control message to carry a fully qualified
* source SUID.
*/
public class LCSourceIDExtension extends LinkControlWord
{
private static final IntField SOURCE_SUID_WACN = IntField.length20(OCTET_2_BIT_16);
private static final IntField SOURCE_SUID_SYSTEM = IntField.length12(OCTET_4_BIT_32 + 4);
private static final IntField SOURCE_SUID_RADIO = IntField.length24(OCTET_6_BIT_48);
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCSourceIDExtension(CorrectedBinaryMessage message)
{
super(message);
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(getMessageStub());
sb.append(" WACN:").append(getWACN());
sb.append(" SYSTEM:").append(getSystem());
sb.append(" ID:").append(getId());
return sb.toString();
}
/**
* Source SUID WACN value.
*/
public int getWACN()
{
return getInt(SOURCE_SUID_WACN);
}
/**
* Source SUID System value.
*/
public int getSystem()
{
return getInt(SOURCE_SUID_SYSTEM);
}
/**
* Source SUID radio value.
*/
public int getId()
{
return getInt(SOURCE_SUID_RADIO);
}
@Override
public List<Identifier> getIdentifiers()
{
return Collections.emptyList();
}
}

View File

@@ -1,45 +1,39 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
/**
* Current user of an APCO25 channel on both inbound and outbound channels
* Status query
*/
public class LCStatusQuery extends LinkControlWord
{
private static final int[] TARGET_ADDRESS = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47};
private static final int[] SOURCE_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_3_BIT_24);
private static final IntField SOURCE_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mTargetAddress;
private Identifier mSourceAddress;
private List<Identifier> mIdentifiers;
@@ -49,7 +43,7 @@ public class LCStatusQuery extends LinkControlWord
*
* @param message
*/
public LCStatusQuery(BinaryMessage message)
public LCStatusQuery(CorrectedBinaryMessage message)
{
super(message);
}
@@ -70,7 +64,7 @@ public class LCStatusQuery extends LinkControlWord
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getMessage().getInt(TARGET_ADDRESS));
mTargetAddress = APCO25RadioIdentifier.createTo(getInt(TARGET_ADDRESS));
}
return mTargetAddress;
@@ -83,7 +77,7 @@ public class LCStatusQuery extends LinkControlWord
{
if(mSourceAddress == null)
{
mSourceAddress = APCO25RadioIdentifier.createFrom(getMessage().getInt(SOURCE_ADDRESS));
mSourceAddress = APCO25RadioIdentifier.createFrom(getInt(SOURCE_ADDRESS));
}
return mSourceAddress;

View File

@@ -1,34 +1,31 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.status.APCO25UnitStatus;
import io.github.dsheirer.module.decode.p25.identifier.status.APCO25UserStatus;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
@@ -37,12 +34,10 @@ import java.util.List;
*/
public class LCStatusUpdate extends LinkControlWord
{
private static final int[] UNIT_STATUS = {8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] USER_STATUS = {16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] TARGET_ADDRESS = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47};
private static final int[] SOURCE_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private static final IntField UNIT_STATUS = IntField.length8(OCTET_1_BIT_8);
private static final IntField USER_STATUS = IntField.length8(OCTET_2_BIT_16);
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_3_BIT_24);
private static final IntField SOURCE_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mUnitStatus;
private Identifier mUserStatus;
@@ -55,7 +50,7 @@ public class LCStatusUpdate extends LinkControlWord
*
* @param message
*/
public LCStatusUpdate(BinaryMessage message)
public LCStatusUpdate(CorrectedBinaryMessage message)
{
super(message);
}

View File

@@ -0,0 +1,123 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.status.APCO25UnitStatus;
import io.github.dsheirer.module.decode.p25.identifier.status.APCO25UserStatus;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.ExtendedSourceLinkControlWord;
import java.util.ArrayList;
import java.util.List;
/**
* Status Update with extended SUID
*/
public class LCStatusUpdateExtended extends ExtendedSourceLinkControlWord
{
private static final IntField UNIT_STATUS = IntField.length8(OCTET_1_BIT_8);
private static final IntField USER_STATUS = IntField.length8(OCTET_2_BIT_16);
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_3_BIT_24);
private Identifier mUnitStatus;
private Identifier mUserStatus;
private Identifier mTargetAddress;
private List<Identifier> mIdentifiers;
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCStatusUpdateExtended(CorrectedBinaryMessage message)
{
super(message);
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(getMessageStub());
sb.append(" TO:").append(getTargetAddress());
if(hasSourceIDExtension())
{
sb.append(" FM:").append(getSourceAddress());
}
sb.append(" UNIT:").append(getUnitStatus());
sb.append(" USER:").append(getUserStatus());
return sb.toString();
}
public Identifier getUnitStatus()
{
if(mUnitStatus == null)
{
mUnitStatus = APCO25UnitStatus.create(getMessage().getInt(UNIT_STATUS));
}
return mUnitStatus;
}
public Identifier getUserStatus()
{
if(mUserStatus == null)
{
mUserStatus = APCO25UserStatus.create(getMessage().getInt(USER_STATUS));
}
return mUserStatus;
}
/**
* Talkgroup address
*/
public Identifier getTargetAddress()
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getMessage().getInt(TARGET_ADDRESS));
}
return mTargetAddress;
}
/**
* List of identifiers contained in this message
*/
@Override
public List<Identifier> getIdentifiers()
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getTargetAddress());
if(hasSourceIDExtension())
{
mIdentifiers.add(getSourceAddress());
}
mIdentifiers.add(getUnitStatus());
mIdentifiers.add(getUserStatus());
}
return mIdentifiers;
}
}

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,16 +14,16 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.Service;
import java.util.Collections;
import java.util.List;
@@ -33,18 +32,16 @@ import java.util.List;
*/
public class LCSystemServiceBroadcast extends LinkControlWord
{
private static final int[] REQUEST_PRIORITY_LEVEL = {20, 21, 22, 23};
private static final int[] AVAILABLE_SERVICES = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47};
private static final int[] SUPPORTED_SERVICES = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
private static final IntField REQUEST_PRIORITY_LEVEL = IntField.length4(OCTET_2_BIT_16 + 4);
private static final IntField AVAILABLE_SERVICES = IntField.length24(OCTET_3_BIT_24);
private static final IntField SUPPORTED_SERVICES = IntField.length24(OCTET_6_BIT_48);
/**
* Constructs a Link Control Word from the binary message sequence.
*
* @param message
*/
public LCSystemServiceBroadcast(BinaryMessage message)
public LCSystemServiceBroadcast(CorrectedBinaryMessage message)
{
super(message);
}
@@ -64,20 +61,18 @@ public class LCSystemServiceBroadcast extends LinkControlWord
*/
public int getRequestPriorityLevel()
{
return getMessage().getInt(REQUEST_PRIORITY_LEVEL);
return getInt(REQUEST_PRIORITY_LEVEL);
}
public List<Service> getAvailableServices()
{
long bitmap = getMessage().getLong(AVAILABLE_SERVICES);
return Service.getServices(bitmap);
return Service.getServices(getInt(AVAILABLE_SERVICES));
}
public List<Service> getSupportedServices()
{
long bitmap = getMessage().getLong(SUPPORTED_SERVICES);
return Service.getServices(bitmap);
return Service.getServices(getInt(SUPPORTED_SERVICES));
}
/**

View File

@@ -1,34 +1,31 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.telephone.APCO25TelephoneNumber;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.Digit;
import java.util.ArrayList;
import java.util.List;
@@ -37,18 +34,17 @@ import java.util.List;
*/
public class LCTelephoneInterconnectAnswerRequest extends LinkControlWord
{
private static final int[] DIGIT_1 = {8, 9, 10, 11};
private static final int[] DIGIT_2 = {12, 13, 14, 15};
private static final int[] DIGIT_3 = {16, 17, 18, 19};
private static final int[] DIGIT_4 = {20, 21, 22, 23};
private static final int[] DIGIT_5 = {24, 25, 26, 27};
private static final int[] DIGIT_6 = {28, 29, 30, 31};
private static final int[] DIGIT_7 = {32, 33, 34, 35};
private static final int[] DIGIT_8 = {36, 37, 38, 39};
private static final int[] DIGIT_9 = {40, 41, 42, 43};
private static final int[] DIGIT_10 = {44, 45, 46, 47};
private static final int[] TARGET_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private static final IntField DIGIT_1 = IntField.length4(OCTET_1_BIT_8);
private static final IntField DIGIT_2 = IntField.length4(OCTET_1_BIT_8 + 4);
private static final IntField DIGIT_3 = IntField.length4(OCTET_2_BIT_16);
private static final IntField DIGIT_4 = IntField.length4(OCTET_2_BIT_16 + 4);
private static final IntField DIGIT_5 = IntField.length4(OCTET_3_BIT_24);
private static final IntField DIGIT_6 = IntField.length4(OCTET_3_BIT_24 + 4);
private static final IntField DIGIT_7 = IntField.length4(OCTET_4_BIT_32);
private static final IntField DIGIT_8 = IntField.length4(OCTET_4_BIT_32 + 4);
private static final IntField DIGIT_9 = IntField.length4(OCTET_5_BIT_40);
private static final IntField DIGIT_10 = IntField.length4(OCTET_5_BIT_40 + 4);
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mTargetAddress;
private Identifier mTelephoneNumber;
@@ -59,7 +55,7 @@ public class LCTelephoneInterconnectAnswerRequest extends LinkControlWord
*
* @param message
*/
public LCTelephoneInterconnectAnswerRequest(BinaryMessage message)
public LCTelephoneInterconnectAnswerRequest(CorrectedBinaryMessage message)
{
super(message);
}
@@ -79,16 +75,16 @@ public class LCTelephoneInterconnectAnswerRequest extends LinkControlWord
if(mTelephoneNumber == null)
{
List<Integer> digits = new ArrayList<>();
digits.add(getMessage().getInt(DIGIT_1));
digits.add(getMessage().getInt(DIGIT_2));
digits.add(getMessage().getInt(DIGIT_3));
digits.add(getMessage().getInt(DIGIT_4));
digits.add(getMessage().getInt(DIGIT_5));
digits.add(getMessage().getInt(DIGIT_6));
digits.add(getMessage().getInt(DIGIT_7));
digits.add(getMessage().getInt(DIGIT_8));
digits.add(getMessage().getInt(DIGIT_9));
digits.add(getMessage().getInt(DIGIT_10));
digits.add(getInt(DIGIT_1));
digits.add(getInt(DIGIT_2));
digits.add(getInt(DIGIT_3));
digits.add(getInt(DIGIT_4));
digits.add(getInt(DIGIT_5));
digits.add(getInt(DIGIT_6));
digits.add(getInt(DIGIT_7));
digits.add(getInt(DIGIT_8));
digits.add(getInt(DIGIT_9));
digits.add(getInt(DIGIT_10));
mTelephoneNumber = APCO25TelephoneNumber.createFrom(Digit.decode(digits));
}
@@ -103,7 +99,7 @@ public class LCTelephoneInterconnectAnswerRequest extends LinkControlWord
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getMessage().getInt(TARGET_ADDRESS));
mTargetAddress = APCO25RadioIdentifier.createTo(getInt(TARGET_ADDRESS));
}
return mTargetAddress;

View File

@@ -1,49 +1,39 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions;
import java.util.ArrayList;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.VoiceLinkControlMessage;
import java.util.Collections;
import java.util.List;
/**
* Current user of an APCO25 channel on both inbound and outbound channels
* Telephone interconnect voice channel user
*/
public class LCTelephoneInterconnectVoiceChannelUser extends LinkControlWord
public class LCTelephoneInterconnectVoiceChannelUser extends VoiceLinkControlMessage
{
private static final int[] RESERVED_1 = {8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] SERVICE_OPTIONS = {16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] RESERVED_2 = {24, 25, 26, 27, 28, 29, 30, 31};
private static final int[] CALL_TIMER = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
private static final int[] ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private VoiceServiceOptions mVoiceServiceOptions;
private static final IntField CALL_TIMER = IntField.length16(OCTET_4_BIT_32);
private static final IntField ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mAddress;
private List<Identifier> mIdentifiers;
@@ -52,7 +42,7 @@ public class LCTelephoneInterconnectVoiceChannelUser extends LinkControlWord
*
* @param message
*/
public LCTelephoneInterconnectVoiceChannelUser(BinaryMessage message)
public LCTelephoneInterconnectVoiceChannelUser(CorrectedBinaryMessage message)
{
super(message);
}
@@ -63,31 +53,18 @@ public class LCTelephoneInterconnectVoiceChannelUser extends LinkControlWord
sb.append(getMessageStub());
sb.append(" ID:").append(getAddress());
sb.append(" CALL TIMER:").append(getCallTimerDuration()).append("MS");
sb.append(" ").append(getVoiceServiceOptions());
sb.append(" ").append(getServiceOptions());
return sb.toString();
}
/**
* Service Options for this channel
*/
public VoiceServiceOptions getVoiceServiceOptions()
{
if(mVoiceServiceOptions == null)
{
mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS));
}
return mVoiceServiceOptions;
}
/**
* Call timer duration in milliseconds.
*/
public long getCallTimerDuration()
{
//Convert from 100 millisecond intervals to milliseconds.
return getMessage().getInt(CALL_TIMER) * 100;
return getInt(CALL_TIMER) * 100;
}
/**
@@ -97,7 +74,7 @@ public class LCTelephoneInterconnectVoiceChannelUser extends LinkControlWord
{
if(mAddress == null)
{
mAddress = APCO25Talkgroup.create(getMessage().getInt(ADDRESS));
mAddress = APCO25Talkgroup.create(getInt(ADDRESS));
}
return mAddress;
@@ -111,8 +88,7 @@ public class LCTelephoneInterconnectVoiceChannelUser extends LinkControlWord
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getAddress());
mIdentifiers = Collections.singletonList(getAddress());
}
return mIdentifiers;

View File

@@ -1,34 +1,30 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.APCO25System;
import io.github.dsheirer.module.decode.p25.identifier.APCO25Wacn;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.List;
@@ -53,7 +49,7 @@ public class LCUnitAuthenticationCommand extends LinkControlWord
*
* @param message
*/
public LCUnitAuthenticationCommand(BinaryMessage message)
public LCUnitAuthenticationCommand(CorrectedBinaryMessage message)
{
super(message);
}

View File

@@ -1,51 +1,43 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.APCO25System;
import io.github.dsheirer.module.decode.p25.identifier.APCO25Wacn;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.identifier.radio.FullyQualifiedRadioIdentifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25FullyQualifiedRadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Unit registration command
* Note: this message is obsolete as of TIA-102.AABF-A-1
*/
public class LCUnitRegistrationCommand extends LinkControlWord
{
private static final int[] WACN = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27};
private static final int[] SYSTEM_ID = {28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
private static final int[] TARGET_ADDRESS = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62, 63};
private static final int[] RESERVED = {64, 65, 66, 67, 68, 69, 70, 71};
private Identifier mWACN;
private Identifier mSystem;
private Identifier mTargetAddress;
private static final IntField WACN = IntField.length20(OCTET_1_BIT_8);
private static final IntField SYSTEM_ID = IntField.length12(OCTET_3_BIT_24 + 4);
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_5_BIT_40);
private FullyQualifiedRadioIdentifier mTargetAddress;
private List<Identifier> mIdentifiers;
/**
@@ -53,7 +45,7 @@ public class LCUnitRegistrationCommand extends LinkControlWord
*
* @param message
*/
public LCUnitRegistrationCommand(BinaryMessage message)
public LCUnitRegistrationCommand(CorrectedBinaryMessage message)
{
super(message);
}
@@ -62,46 +54,22 @@ public class LCUnitRegistrationCommand extends LinkControlWord
{
StringBuilder sb = new StringBuilder();
sb.append(getMessageStub());
sb.append(" WACN:").append(getWACN());
sb.append(" SYSTEM:").append(getSystem());
sb.append(" RADIO:").append(getTargetAddress());
return sb.toString();
}
/**
* WACN
* Target address
*/
public Identifier getWACN()
{
if(mWACN == null)
{
mWACN = APCO25Wacn.create(getMessage().getInt(WACN));
}
return mWACN;
}
/**
* System
*/
public Identifier getSystem()
{
if(mSystem == null)
{
mSystem = APCO25System.create(getMessage().getInt(SYSTEM_ID));
}
return mSystem;
}
/**
* Source address
*/
public Identifier getTargetAddress()
public FullyQualifiedRadioIdentifier getTargetAddress()
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getMessage().getInt(TARGET_ADDRESS));
//No persona ... reuse the radio ID.
int wacn = getInt(WACN);
int system = getInt(SYSTEM_ID);
int radio = getInt(TARGET_ADDRESS);
mTargetAddress = APCO25FullyQualifiedRadioIdentifier.createTo(radio, wacn, system, radio);
}
return mTargetAddress;
@@ -115,10 +83,7 @@ public class LCUnitRegistrationCommand extends LinkControlWord
{
if(mIdentifiers == null)
{
mIdentifiers = new ArrayList<>();
mIdentifiers.add(getWACN());
mIdentifiers.add(getSystem());
mIdentifiers.add(getTargetAddress());
mIdentifiers = Collections.singletonList(getTargetAddress());
}
return mIdentifiers;

View File

@@ -1,49 +1,39 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.VoiceLinkControlMessage;
import java.util.ArrayList;
import java.util.List;
/**
* Current user of an APCO25 channel on both inbound and outbound channels
* Unit to unit answer request
*/
public class LCUnitToUnitAnswerRequest extends LinkControlWord
public class LCUnitToUnitAnswerRequest extends VoiceLinkControlMessage
{
private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] RESERVED = {16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] TARGET_ADDRESS = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47};
private static final int[] SOURCE_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private VoiceServiceOptions mVoiceServiceOptions;
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_3_BIT_24);
private static final IntField SOURCE_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mTargetAddress;
private Identifier mSourceAddress;
private List<Identifier> mIdentifiers;
@@ -53,7 +43,7 @@ public class LCUnitToUnitAnswerRequest extends LinkControlWord
*
* @param message
*/
public LCUnitToUnitAnswerRequest(BinaryMessage message)
public LCUnitToUnitAnswerRequest(CorrectedBinaryMessage message)
{
super(message);
}
@@ -64,23 +54,10 @@ public class LCUnitToUnitAnswerRequest extends LinkControlWord
sb.append(getMessageStub());
sb.append(" TO:").append(getTargetAddress());
sb.append(" FM:").append(getSourceAddress());
sb.append(" ").append(getVoiceServiceOptions());
sb.append(" ").append(getServiceOptions());
return sb.toString();
}
/**
* Service Options for this channel
*/
public VoiceServiceOptions getVoiceServiceOptions()
{
if(mVoiceServiceOptions == null)
{
mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS));
}
return mVoiceServiceOptions;
}
/**
* Talkgroup address
*/
@@ -88,7 +65,7 @@ public class LCUnitToUnitAnswerRequest extends LinkControlWord
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getMessage().getInt(TARGET_ADDRESS));
mTargetAddress = APCO25RadioIdentifier.createTo(getInt(TARGET_ADDRESS));
}
return mTargetAddress;
@@ -101,7 +78,7 @@ public class LCUnitToUnitAnswerRequest extends LinkControlWord
{
if(mSourceAddress == null)
{
mSourceAddress = APCO25RadioIdentifier.createFrom(getMessage().getInt(SOURCE_ADDRESS));
mSourceAddress = APCO25RadioIdentifier.createFrom(getInt(SOURCE_ADDRESS));
}
return mSourceAddress;

View File

@@ -1,48 +1,39 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard;
import io.github.dsheirer.bits.BinaryMessage;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.bits.IntField;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.p25.identifier.radio.APCO25RadioIdentifier;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord;
import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions;
import io.github.dsheirer.module.decode.p25.phase1.message.lc.VoiceLinkControlMessage;
import java.util.ArrayList;
import java.util.List;
/**
* Current user of an APCO25 channel on both inbound and outbound channels
* Unit to Unit voice channel user
*/
public class LCUnitToUnitVoiceChannelUser extends LinkControlWord
public class LCUnitToUnitVoiceChannelUser extends VoiceLinkControlMessage
{
private static final int[] SERVICE_OPTIONS = {16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] TARGET_ADDRESS = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47};
private static final int[] SOURCE_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71};
private VoiceServiceOptions mVoiceServiceOptions;
private static final IntField TARGET_ADDRESS = IntField.length24(OCTET_3_BIT_24);
private static final IntField SOURCE_ADDRESS = IntField.length24(OCTET_6_BIT_48);
private Identifier mTargetAddress;
private Identifier mSourceAddress;
private List<Identifier> mIdentifiers;
@@ -52,7 +43,7 @@ public class LCUnitToUnitVoiceChannelUser extends LinkControlWord
*
* @param message
*/
public LCUnitToUnitVoiceChannelUser(BinaryMessage message)
public LCUnitToUnitVoiceChannelUser(CorrectedBinaryMessage message)
{
super(message);
}
@@ -63,23 +54,10 @@ public class LCUnitToUnitVoiceChannelUser extends LinkControlWord
sb.append(getMessageStub());
sb.append(" TO:").append(getTargetAddress());
sb.append(" FM:").append(getSourceAddress());
sb.append(" ").append(getVoiceServiceOptions());
sb.append(" ").append(getServiceOptions());
return sb.toString();
}
/**
* Service Options for this channel
*/
public VoiceServiceOptions getVoiceServiceOptions()
{
if(mVoiceServiceOptions == null)
{
mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS));
}
return mVoiceServiceOptions;
}
/**
* Talkgroup address
*/
@@ -87,7 +65,7 @@ public class LCUnitToUnitVoiceChannelUser extends LinkControlWord
{
if(mTargetAddress == null)
{
mTargetAddress = APCO25RadioIdentifier.createTo(getMessage().getInt(TARGET_ADDRESS));
mTargetAddress = APCO25RadioIdentifier.createTo(getInt(TARGET_ADDRESS));
}
return mTargetAddress;
@@ -100,7 +78,7 @@ public class LCUnitToUnitVoiceChannelUser extends LinkControlWord
{
if(mSourceAddress == null)
{
mSourceAddress = APCO25RadioIdentifier.createFrom(getMessage().getInt(SOURCE_ADDRESS));
mSourceAddress = APCO25RadioIdentifier.createFrom(getInt(SOURCE_ADDRESS));
}
return mSourceAddress;

Some files were not shown because too many files have changed in this diff Show More