diff --git a/.gitignore b/.gitignore index 6633be8cf..e4a1c09b3 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,7 @@ out/ *.class *.log # Package Files # -*.jar +#*.jar # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* diff --git a/.idea/compiler.xml b/.idea/compiler.xml index cb7eff953..967a782f9 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -4,6 +4,8 @@ + + \ No newline at end of file diff --git a/.idea/libraries/imports.xml b/.idea/libraries/imports.xml index b90eef82b..2bdceef59 100644 --- a/.idea/libraries/imports.xml +++ b/.idea/libraries/imports.xml @@ -1,12 +1,10 @@ - - - + diff --git a/.idea/modules.xml b/.idea/modules.xml index f67d0d5be..5e8edec26 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,9 +2,11 @@ - + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7c48cf89c..045362c3c 100644 --- a/build.gradle +++ b/build.gradle @@ -47,6 +47,7 @@ dependencies { compile 'ch.qos.logback:logback-core:1.2.3' compile 'ch.qos.logback:logback-classic:1.2.3' compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.8' + compile 'com.fazecast:jSerialComm:2.5.0' compile 'com.github.jiconfont:jiconfont-font_awesome:4.7.0.1' compile 'com.github.jiconfont:jiconfont-javafx:1.0.0' compile 'com.github.jiconfont:jiconfont-swing:1.0.1' @@ -54,6 +55,7 @@ dependencies { compile 'com.google.guava:guava:27.0.1-jre' compile 'com.jidesoft:jide-oss:3.6.18' compile 'com.miglayout:miglayout-swing:5.2' + compile 'eu.hansolo:charts:1.0.5' compile 'io.github.dsheirer:radio-reference-api:15.0.1' compile 'javax.usb:usb-api:1.0.2' compile 'net.coderazzi:tablefilter-swing:5.4.0' @@ -100,7 +102,7 @@ task buildSdr(type: Jar) { attributes 'Implementation-Title': 'SdrTrunk project', 'Implementation-Version': version, 'Main-Class': 'io.github.dsheirer.gui.SDRTrunk', - 'Class-Path': 'jmbe-0.3.2.jar jmbe-0.3.3.jar' + 'Class-Path': 'jmbe-1.0.0.jar' } baseName = project.name + '-all' from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } diff --git a/imports/jmbe-interface-0.3.3.jar b/imports/jmbe-api-1.0.0.jar similarity index 73% rename from imports/jmbe-interface-0.3.3.jar rename to imports/jmbe-api-1.0.0.jar index 73fac2869..9e398e186 100644 Binary files a/imports/jmbe-interface-0.3.3.jar and b/imports/jmbe-api-1.0.0.jar differ diff --git a/sdr-trunk.ipr b/sdr-trunk.ipr index f3b4d0ecb..9ff6b03bd 100644 --- a/sdr-trunk.ipr +++ b/sdr-trunk.ipr @@ -11,9 +11,9 @@ - - - + + + @@ -36,6 +36,7 @@ - + - + @@ -255,48 +256,48 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -310,6 +311,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -343,26 +399,26 @@ - + - + - + - + - + - + - + - + @@ -394,26 +450,26 @@ - + - + - + - + - + - + - + - + @@ -427,53 +483,59 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + + + + + - + - + - + + + - + @@ -498,26 +560,26 @@ - + - + - + - + - + - + - + - + @@ -575,37 +637,158 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + diff --git a/src/main/java/io/github/dsheirer/audio/AudioModule.java b/src/main/java/io/github/dsheirer/audio/AudioModule.java index 2d034ca12..d8be85dcb 100644 --- a/src/main/java/io/github/dsheirer/audio/AudioModule.java +++ b/src/main/java/io/github/dsheirer/audio/AudioModule.java @@ -1,25 +1,28 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.audio; import io.github.dsheirer.audio.squelch.SquelchState; +import io.github.dsheirer.audio.squelch.SquelchStateEvent; import io.github.dsheirer.dsp.filter.design.FilterDesignException; import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification; import io.github.dsheirer.dsp.filter.fir.real.RealFIRFilter2; @@ -136,7 +139,7 @@ public void stop() @Override - public Listener getSquelchStateListener() + public Listener getSquelchStateListener() { return mSquelchStateListener; } @@ -169,7 +172,7 @@ public void receive(ReusableFloatBuffer reusableFloatBuffer) } @Override - public Listener getReusableBufferListener() + public Listener getReusableBufferListener() { //Redirect received reusable buffers to the receive(buffer) method return this; @@ -178,12 +181,12 @@ public Listener getReusableBufferListener() /** * Wrapper for squelch state listener */ - public class SquelchStateListener implements Listener + public class SquelchStateListener implements Listener { @Override - public void receive(SquelchState state) + public void receive(SquelchStateEvent event) { - if(state == SquelchState.SQUELCH && hasAudioPacketListener()) + if(event.getSquelchState() == SquelchState.SQUELCH && hasAudioPacketListener()) { ReusableAudioPacket endAudioPacket = mAudioPacketQueue.getEndAudioBuffer(); endAudioPacket.resetAttributes(); @@ -192,7 +195,7 @@ public void receive(SquelchState state) getAudioPacketListener().receive(endAudioPacket); } - mSquelchState = state; + mSquelchState = event.getSquelchState(); } } } diff --git a/src/main/java/io/github/dsheirer/audio/codec/mbe/AmbeAudioModule.java b/src/main/java/io/github/dsheirer/audio/codec/mbe/AmbeAudioModule.java new file mode 100644 index 000000000..714cddbc2 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/codec/mbe/AmbeAudioModule.java @@ -0,0 +1,59 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.codec.mbe; + +import io.github.dsheirer.preference.UserPreferences; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AmbeAudioModule extends JmbeAudioModule +{ + private static final Logger mLog = LoggerFactory.getLogger(AmbeAudioModule.class); + private static final String AMBE_CODEC = "AMBE 3600 x 2450"; + private static boolean sLibraryStatusLogged = false; + + public AmbeAudioModule(UserPreferences userPreferences) + { + super(userPreferences); + + if(!sLibraryStatusLogged) + { + if(getAudioCodec() != null) + { + mLog.info("AMBE CODEC successfully loaded - P25-2/DMR/NXDN audio will be available"); + } + else + { + mLog.warn("AMBE CODEC not loaded - P25-2/DMR/NXDN audio will NOT be available"); + } + + sLibraryStatusLogged = true; + } + } + + @Override + protected String getCodecName() + { + return AMBE_CODEC; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/codec/mbe/IEncryptionSyncParameters.java b/src/main/java/io/github/dsheirer/audio/codec/mbe/IEncryptionSyncParameters.java new file mode 100644 index 000000000..284f5b764 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/codec/mbe/IEncryptionSyncParameters.java @@ -0,0 +1,42 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.codec.mbe; + +import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier; + +/** + * P25 Encryption Parameters + */ +public interface IEncryptionSyncParameters +{ + /** + * Encryption key identifier + */ + EncryptionKeyIdentifier getEncryptionKey(); + + /** + * Message Indicator + * @return key generator fill values + */ + String getMessageIndicator(); +} diff --git a/src/main/java/io/github/dsheirer/audio/codec/mbe/ImbeAudioModule.java b/src/main/java/io/github/dsheirer/audio/codec/mbe/ImbeAudioModule.java new file mode 100644 index 000000000..8a94870e3 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/codec/mbe/ImbeAudioModule.java @@ -0,0 +1,59 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.codec.mbe; + +import io.github.dsheirer.preference.UserPreferences; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class ImbeAudioModule extends JmbeAudioModule +{ + private static final Logger mLog = LoggerFactory.getLogger(ImbeAudioModule.class); + private static final String IMBE_CODEC = "IMBE"; + private static boolean sLibraryStatusLogged = false; + + public ImbeAudioModule(UserPreferences userPreferences) + { + super(userPreferences); + + if(!sLibraryStatusLogged) + { + if(getAudioCodec() != null) + { + mLog.info("JMBE audio conversion library IMBE CODEC successfully loaded - P25-1 audio will be available"); + } + else + { + mLog.warn("JMBE audio conversion library, IMBE CODEC not loaded - P25-1 audio will NOT be available"); + } + + sLibraryStatusLogged = true; + } + } + + @Override + protected String getCodecName() + { + return IMBE_CODEC; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/codec/mbe/JmbeAudioModule.java b/src/main/java/io/github/dsheirer/audio/codec/mbe/JmbeAudioModule.java new file mode 100644 index 000000000..2a27531cc --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/codec/mbe/JmbeAudioModule.java @@ -0,0 +1,248 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.codec.mbe; + +import com.google.common.eventbus.Subscribe; +import io.github.dsheirer.audio.AbstractAudioModule; +import io.github.dsheirer.eventbus.MyEventBus; +import io.github.dsheirer.message.IMessage; +import io.github.dsheirer.message.IMessageListener; +import io.github.dsheirer.preference.PreferenceType; +import io.github.dsheirer.preference.UserPreferences; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableAudioPacketQueue; +import jmbe.iface.IAudioCodec; +import jmbe.iface.IAudioCodecLibrary; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +public abstract class JmbeAudioModule extends AbstractAudioModule implements Listener, IMessageListener +{ + private static final Logger mLog = LoggerFactory.getLogger(JmbeAudioModule.class); + private static final String JMBE_AUDIO_LIBRARY = "JMBE"; + private static List mLibraryLoadStatusLogged = new ArrayList<>(); + private IAudioCodec mAudioCodec; + private UserPreferences mUserPreferences; + private ReusableAudioPacketQueue mAudioPacketQueue = new ReusableAudioPacketQueue("JmbeAudioModule"); + + public JmbeAudioModule(UserPreferences userPreferences) + { + mUserPreferences = userPreferences; + MyEventBus.getEventBus().register(this); + loadConverter(); + } + + protected IAudioCodec getAudioCodec() + { + return mAudioCodec; + } + + /** + * Indicates that the JMBE audio library has been loaded and a suitable audio codec is usable (ie non-null) + */ + protected boolean hasAudioCodec() + { + return getAudioCodec() != null; + } + + protected ReusableAudioPacketQueue getAudioPacketQueue() + { + return mAudioPacketQueue; + } + + @Override + public Listener getMessageListener() + { + return this; + } + + /** + * Receives notifications that the JMBE library preference has been updated via the Guava event bus + * + * @param preferenceType that was updated + */ + @Subscribe + public void preferenceUpdated(PreferenceType preferenceType) + { + if(preferenceType == PreferenceType.JMBE_LIBRARY) + { + mLibraryLoadStatusLogged.clear(); + loadConverter(); + } + } + + /** + * Name of the CODEC to use from the JMBE library + */ + protected abstract String getCodecName(); + + /** + * Loads audio frame processing chain. Constructs an imbe targetdataline + * to receive the raw imbe frames. Adds an IMBE to 8k PCM format conversion + * stream wrapper. Finally, adds an upsampling (8k to 48k) stream wrapper. + */ + protected void loadConverter() + { + IAudioCodec audioConverter = null; + + Path path = mUserPreferences.getJmbeLibraryPreference().getPathJmbeLibrary(); + + if(path != null) + { + try + { + if(!mLibraryLoadStatusLogged.contains(JMBE_AUDIO_LIBRARY)) + { + mLog.info("Loading JMBE library from [" + path.toString() + "]"); + } + + URLClassLoader childClassLoader = new URLClassLoader(new URL[]{path.toUri().toURL()}, + this.getClass().getClassLoader()); + + Class classToLoad = Class.forName("jmbe.JMBEAudioLibrary", true, childClassLoader); + + Object instance = classToLoad.getDeclaredConstructor().newInstance(); + + if(instance instanceof IAudioCodecLibrary) + { + IAudioCodecLibrary library = (IAudioCodecLibrary)instance; + + if((library.getMajorVersion() == 1 && library.getMinorVersion() >= 0 && + library.getBuildVersion() >= 0) || library.getMajorVersion() >= 1) + { + audioConverter = library.getAudioConverter(getCodecName()); + + if(!mLibraryLoadStatusLogged.contains(JMBE_AUDIO_LIBRARY)) + { + mLog.info("JMBE audio conversion library loaded: " + library.getVersion()); + mLibraryLoadStatusLogged.add(JMBE_AUDIO_LIBRARY); + } + } + else + { + if(!mLibraryLoadStatusLogged.contains(JMBE_AUDIO_LIBRARY)) + { + mLog.warn("JMBE library version 1.0.0 or higher is required - found: " + library.getVersion()); + mLibraryLoadStatusLogged.add(JMBE_AUDIO_LIBRARY); + } + } + } + else + { + if(!mLibraryLoadStatusLogged.contains(JMBE_AUDIO_LIBRARY)) + { + mLog.info("JMBE audio conversion library NOT FOUND"); + mLibraryLoadStatusLogged.add(JMBE_AUDIO_LIBRARY); + } + } + } + catch(IllegalArgumentException iae) + { + if(!mLibraryLoadStatusLogged.contains(JMBE_AUDIO_LIBRARY + getCodecName())) + { + mLog.error("Couldn't load JMBE audio conversion library - " + iae.getMessage()); + mLibraryLoadStatusLogged.add(JMBE_AUDIO_LIBRARY + getCodecName()); + } + } + catch(NoSuchMethodException nsme) + { + if(!mLibraryLoadStatusLogged.contains(JMBE_AUDIO_LIBRARY)) + { + mLog.error("Couldn't load JMBE audio conversion library - no such method exception"); + mLibraryLoadStatusLogged.add(JMBE_AUDIO_LIBRARY); + } + } + catch(MalformedURLException mue) + { + if(!mLibraryLoadStatusLogged.contains(JMBE_AUDIO_LIBRARY)) + { + mLog.error("Couldn't load JMBE audio conversion library from path [" + path + "]"); + mLibraryLoadStatusLogged.add(JMBE_AUDIO_LIBRARY); + } + } + catch(ClassNotFoundException e1) + { + if(!mLibraryLoadStatusLogged.contains(JMBE_AUDIO_LIBRARY)) + { + mLog.error("Couldn't load JMBE audio conversion library - class not found"); + mLibraryLoadStatusLogged.add(JMBE_AUDIO_LIBRARY); + } + } + catch(InvocationTargetException ite) + { + if(!mLibraryLoadStatusLogged.contains(JMBE_AUDIO_LIBRARY)) + { + mLog.error("Couldn't load JMBE audio conversion library - invocation target exception", ite); + mLibraryLoadStatusLogged.add(JMBE_AUDIO_LIBRARY); + } + } + catch(InstantiationException e1) + { + if(!mLibraryLoadStatusLogged.contains(JMBE_AUDIO_LIBRARY)) + { + mLog.error("Couldn't load JMBE audio conversion library - instantiation exception", e1); + mLibraryLoadStatusLogged.add(JMBE_AUDIO_LIBRARY); + } + } + catch(IllegalAccessException e1) + { + if(!mLibraryLoadStatusLogged.contains(JMBE_AUDIO_LIBRARY)) + { + mLog.error("Couldn't load JMBE audio conversion library - security restrictions"); + mLibraryLoadStatusLogged.add(JMBE_AUDIO_LIBRARY); + } + } + } + else + { + if(!mLibraryLoadStatusLogged.contains(JMBE_AUDIO_LIBRARY)) + { + mLog.warn("JMBE audio library path is NOT SET in your User Preferences."); + mLibraryLoadStatusLogged.add(JMBE_AUDIO_LIBRARY); + } + } + + if(audioConverter != null) + { + mAudioCodec = audioConverter; + } + else + { + mAudioCodec = null; + } + } + + @Override + public void dispose() + { + mAudioCodec = null; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/codec/mbe/MBECallSequence.java b/src/main/java/io/github/dsheirer/audio/codec/mbe/MBECallSequence.java new file mode 100644 index 000000000..15776dd5f --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/codec/mbe/MBECallSequence.java @@ -0,0 +1,291 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.codec.mbe; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonRootName; +import io.github.dsheirer.identifier.encryption.EncryptionKey; +import io.github.dsheirer.module.decode.p25.audio.VoiceFrame; + +import java.util.ArrayList; +import java.util.List; + +/** + * MBE Call Sequence containing one or more voice frames with optional encryption parameters and optional from and to + * radio identifiers. + */ +@JsonRootName("mbe_call") +@JsonPropertyOrder({"protocol", "call_type", "from", "to", "encrypted", "frames"}) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class MBECallSequence +{ + private String mProtocol; + private String mFromIdentifier; + private String mToIdentifier; + private String mCallType; + private String mSystem; + private String mSite; + private boolean mEncrypted; + private List mVoiceFrames = new ArrayList<>(); + private IEncryptionSyncParameters mTemporaryEncryptionSyncParameters; + + /** + * Constructs a call sequence + */ + public MBECallSequence(String protocol) + { + mProtocol = protocol; + } + + public MBECallSequence() + { + //no-arg constructor for faster jackson deserialization + } + + /** + * Protocol/format for the voice frames + */ + @JsonProperty("protocol") + public String getProtocol() + { + return mProtocol; + } + + public void setProtocol(String protocol) + { + mProtocol = protocol; + } + + + /** + * Indicates if this sequences contains any audio frames + */ + @JsonIgnore + public boolean hasAudio() + { + return mVoiceFrames.size() > 4; + } + + /** + * Indicates if this call sequence is encrypted + */ + @JsonProperty("encrypted") + public boolean isEncrypted() + { + return mEncrypted; + } + + /** + * Sets the encrypted status of this call sequence + * + * @param encrypted status + */ + public void setEncrypted(boolean encrypted) + { + mEncrypted = encrypted; + } + + /** + * Sets encryption sync parameters to use with the next sequence of voice frames. This is usually obtained from the + * HDU (phase1) or the PTT (phase2) + * + * @param encryptionSyncParameters to apply to the next set of voice frames + */ + public void setEncryptionSyncParameters(IEncryptionSyncParameters encryptionSyncParameters) + { + mTemporaryEncryptionSyncParameters = encryptionSyncParameters; + } + + /** + * Sets the from radio identifier + * + * @param from id + */ + public void setFromIdentifier(String from) + { + if(from != null && !from.isEmpty() && !from.contentEquals("0")) + { + mFromIdentifier = from; + } + } + + /** + * Radio identifier that originated the call + * + * @return from id + */ + @JsonProperty("from") + public String getFromIdentifier() + { + return mFromIdentifier; + } + + /** + * Sets the to radio identifier + * + * @param to id + */ + public void setToIdentifier(String to) + { + if(to != null && !to.isEmpty() && !to.contentEquals("0")) + { + mToIdentifier = to; + } + } + + /** + * Radio identifier that received the call + * + * @return to id + */ + @JsonProperty("to") + public String getToIdentifier() + { + return mToIdentifier; + } + + /** + * Call type + * + * @param type from GROUP, INDIVIDUAL, or TELEPHONE INTERCONNECT + */ + public void setCallType(String type) + { + mCallType = type; + } + + /** + * Sets the call type + * + * @return call type + */ + @JsonProperty("call_type") + public String getCallType() + { + return mCallType; + } + + /** + * System name defined by the user + * @return + */ + @JsonProperty("system") + public String getSystem() + { + return mSystem; + } + + /** + * Sets the system name + * @param system + */ + public void setSystem(String system) + { + mSystem = system; + } + + /** + * Site name defined by the user + * @return + */ + @JsonProperty("site") + public String getSite() + { + return mSite; + } + + /** + * Sets the site name + * @param site + */ + public void setSite(String site) + { + mSite = site; + } + + /** + * Ordered list of voice frames for the call sequence + * + * @return list of unencrypted or encrypted audio frames + */ + @JsonProperty("frames") + public List getVoiceFrames() + { + return mVoiceFrames; + } + + public void setVoiceFrames(List voiceFrames) + { + mVoiceFrames = voiceFrames; + } + + /** + * Adds an unencrypted audio frame to this call sequence + * + * @param timestamp of the audio frame + * @param frame of hexadecimal values representing the transmitted audio frame and ecc bits + */ + public void addVoiceFrame(long timestamp, String frame) + { + if(mTemporaryEncryptionSyncParameters != null) + { + addEncryptedVoiceFrame(timestamp, frame, mTemporaryEncryptionSyncParameters); + mTemporaryEncryptionSyncParameters = null; + } + else + { + mVoiceFrames.add(new VoiceFrame(timestamp, frame)); + } + } + + /** + * Adds an encrypted audio frame to this call sequence + * + * @param timestamp of the audio frame + * @param frame of hexadecimal values representing the transmitted audio frame and ecc bits + * @param parameters identifying the encryption used for the frame + */ + public void addEncryptedVoiceFrame(long timestamp, String frame, IEncryptionSyncParameters parameters) + { + EncryptionKey encryption = parameters.getEncryptionKey().getValue(); + addEncryptedVoiceFrame(timestamp, frame, encryption.getAlgorithm(), encryption.getKey(), parameters.getMessageIndicator()); + setEncrypted(true); + } + + /** + * Adds an encrypted audio frame to this call sequence + * + * @param timestamp of the audio frame + * @param frame of hexadecimal values representing the transmitted audio frame and ecc bits + * @param algorithm identifier for encryption + * @param keyid identifying which encryption key was used by the radio which may have multiple keys + * @param messageIndicator to seed the key generator + */ + public void addEncryptedVoiceFrame(long timestamp, String frame, int algorithm, int keyid, String messageIndicator) + { + mVoiceFrames.add(new VoiceFrame(timestamp, frame, algorithm, keyid, messageIndicator)); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/codec/mbe/MBECallSequenceConverter.java b/src/main/java/io/github/dsheirer/audio/codec/mbe/MBECallSequenceConverter.java new file mode 100644 index 000000000..f879e7288 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/codec/mbe/MBECallSequenceConverter.java @@ -0,0 +1,122 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.codec.mbe; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.github.dsheirer.audio.convert.thumbdv.ThumbDv; +import io.github.dsheirer.audio.convert.thumbdv.message.response.AmbeResponse; +import io.github.dsheirer.module.decode.p25.audio.VoiceFrame; +import io.github.dsheirer.record.wave.AudioPacketWaveRecorder; +import io.github.dsheirer.record.wave.WaveMetadata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Utility for converting MBE call sequences (*.mbe) to PCM wave audio format + */ +public class MBECallSequenceConverter +{ + private final static Logger mLog = LoggerFactory.getLogger(MBECallSequenceConverter.class); + + public static void convert(Path input, Path output) throws IOException + { + InputStream inputStream = Files.newInputStream(input); + ObjectMapper mapper = new ObjectMapper(); + MBECallSequence sequence = mapper.readValue(inputStream, MBECallSequence.class); + convert(sequence, output); + } + + public static void convert(MBECallSequence callSequence, Path outputPath) + { + if(callSequence == null || callSequence.isEncrypted()) + { + throw new IllegalArgumentException("Cannot decode null or encrypted call sequence"); + } + + if(callSequence != null && !callSequence.isEncrypted()) + { + ThumbDv.AudioProtocol protocol = ThumbDv.AudioProtocol.P25_PHASE2; + + AudioPacketWaveRecorder recorder = new AudioPacketWaveRecorder(outputPath); + recorder.start(); + + long delayMillis = 0; + + try(ThumbDv thumbDv = new ThumbDv(protocol, recorder)) + { + thumbDv.start(); + for(VoiceFrame voiceFrame: callSequence.getVoiceFrames()) + { + mLog.debug("Frame [" + voiceFrame.getFrame() + "] + Hex [" + AmbeResponse.toHex(voiceFrame.getFrameBytes()) + "]"); + thumbDv.decode(voiceFrame.getFrameBytes()); + delayMillis += 30; + } + + if(delayMillis > 0) + { + delayMillis += 1000; + try + { + Thread.sleep(delayMillis); + } + catch(InterruptedException ie) + { + + } + } + } + catch(IOException ioe) + { + mLog.error("Error", ioe); + } + + recorder.stop(Paths.get(outputPath.toString().replace(".tmp", ".wav")), new WaveMetadata()); + } + } + + public static void main(String[] args) + { +// String mbe = "/home/denny/SDRTrunk/recordings/20190331085324_154250000_3_TS0_65084_6591007.mbe"; +// String mbe = "/home/denny/SDRTrunk/recordings/20190331085324_154250000_2_TS1_65035.mbe"; +// +// Path input = Paths.get(mbe); +// Path output = Paths.get(mbe.replace(".mbe", ".tmp")); +// +// mLog.info("Converting: " + mbe); +// +// try +// { +// MBECallSequenceConverter.convert(input, output); +// } +// catch(IOException ioe) +// { +// mLog.error("Error", ioe); +// } + } +} diff --git a/src/main/java/io/github/dsheirer/audio/codec/mbe/MBECallSequenceReader.java b/src/main/java/io/github/dsheirer/audio/codec/mbe/MBECallSequenceReader.java new file mode 100644 index 000000000..be9b48643 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/codec/mbe/MBECallSequenceReader.java @@ -0,0 +1,79 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.codec.mbe; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Joiner; +import io.github.dsheirer.module.decode.p25.audio.VoiceFrame; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Reader for MBE call sequence recordings + */ +public class MBECallSequenceReader +{ + public static List getAudioFrames(Path path) throws IOException + { + ObjectMapper mapper = new ObjectMapper(); + Object obj = mapper.readValue(path.toFile(), MBECallSequence.class); + + if(obj instanceof MBECallSequence) + { + MBECallSequence sequence = (MBECallSequence)obj; + + List audioFrames = new ArrayList<>(); + + for(VoiceFrame voiceFrame: sequence.getVoiceFrames()) + { + audioFrames.add(voiceFrame.getFrame()); + } + + return audioFrames; + } + + return Collections.emptyList(); + } + + public static void main(String[] args) + { + Path path = Path.of("/home/denny/SDRTrunk/recordings/20190706063149_154250000_7_TS1_65084_6591001.mbe"); + + try + { + List frames = MBECallSequenceReader.getAudioFrames(path); + + Files.writeString(Path.of("/home/denny/SDRTrunk/recordings/mbe_frames.txt"), Joiner.on("\",\n\"").join(frames)); + } + catch(Exception e) + { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/io/github/dsheirer/audio/codec/mbe/MBECallSequenceRecorder.java b/src/main/java/io/github/dsheirer/audio/codec/mbe/MBECallSequenceRecorder.java new file mode 100644 index 000000000..459a9a2f9 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/codec/mbe/MBECallSequenceRecorder.java @@ -0,0 +1,163 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.codec.mbe; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.github.dsheirer.message.IMessage; +import io.github.dsheirer.message.IMessageListener; +import io.github.dsheirer.module.Module; +import io.github.dsheirer.preference.TimestampFormat; +import io.github.dsheirer.preference.UserPreferences; +import io.github.dsheirer.sample.Listener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Date; + +/** + * Records MBE audio frame call sequences and metadata to a JSON format recording file + */ +public abstract class MBECallSequenceRecorder extends Module implements IMessageListener, Listener +{ + private final static Logger mLog = LoggerFactory.getLogger(MBECallSequenceRecorder.class); + + protected static final String CALL_TYPE_GROUP = "GROUP"; + protected static final String CALL_TYPE_INDIVIDUAL = "INDIVIDUAL"; + protected static final String CALL_TYPE_TELEPHONE_INTERCONNECT = "TELEPHONE INTERCONNECT"; + protected UserPreferences mUserPreferences; + protected long mChannelFrequency; + protected String mSystem; + protected String mSite; + private int mCallNumber = 1; + + /** + * Constructs an instance + * @param userPreferences to obtain recording directory + * @param channelFrequency for the channel to record + */ + public MBECallSequenceRecorder(UserPreferences userPreferences, long channelFrequency, String system, String site) + { + mUserPreferences = userPreferences; + mChannelFrequency = channelFrequency; + mSystem = system; + mSite = site; + } + + @Override + public void reset() + { + } + + @Override + public void start() + { + } + + @Override + public void dispose() + { + } + + /** + * Writes an MBE call sequence recording to the recording directory + * @param sequence to write + */ + protected void writeCallSequence(MBECallSequence sequence) + { + writeCallSequence(sequence, null); + } + + /** + * Writes an MBE call sequence recording to the recording directory. + * + * @param optionalChannelTag to include in the filename + * @param sequence containing voice frames + */ + protected void writeCallSequence(MBECallSequence sequence, String optionalChannelTag) + { + if(sequence != null && sequence.hasAudio()) + { + sequence.setSystem(mSystem); + sequence.setSite(mSite); + + StringBuilder sb = new StringBuilder(); + sb.append(TimestampFormat.TIMESTAMP_COMPACT.getFormatter().format(new Date(System.currentTimeMillis()))); + sb.append("_").append(mChannelFrequency); + sb.append("_").append(mCallNumber++); + + if(mCallNumber < 1) + { + mCallNumber = 1; + } + + if(optionalChannelTag != null) + { + sb.append("_").append(optionalChannelTag); + } + + if(sequence.getToIdentifier() != null) + { + sb.append("_").append(sequence.getToIdentifier().replace(":", "")); + } + if(sequence.getFromIdentifier() != null) + { + sb.append("_").append(sequence.getFromIdentifier().replace(":", "")); + } + + if(sequence.isEncrypted()) + { + sb.append("_encrypted"); + } + + sb.append(".mbe"); + + Path recordingDirectory = mUserPreferences.getDirectoryPreference().getDirectoryRecording(); + Path filePath = recordingDirectory.resolve(sb.toString()); + + try + { + OutputStream outputStream = Files.newOutputStream(filePath); + ObjectMapper mapper = new ObjectMapper(); + mapper.writerWithDefaultPrettyPrinter().writeValue(outputStream, sequence); + outputStream.close(); + } + catch(IOException ioe) + { + mLog.error("Couldn't write MBE call sequence to path [" + filePath.toString() + "]", ioe); + } + } + } + + /** + * Implementation of IMessageListener interface + */ + @Override + public Listener getMessageListener() + { + return this; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/ThumbDv.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/ThumbDv.java new file mode 100644 index 000000000..d791c10f1 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/ThumbDv.java @@ -0,0 +1,492 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv; + +import com.fazecast.jSerialComm.SerialPort; +import io.github.dsheirer.audio.convert.thumbdv.message.AmbeMessage; +import io.github.dsheirer.audio.convert.thumbdv.message.AmbeMessageFactory; +import io.github.dsheirer.audio.convert.thumbdv.message.VocoderRate; +import io.github.dsheirer.audio.convert.thumbdv.message.request.AmbeRequest; +import io.github.dsheirer.audio.convert.thumbdv.message.request.DecodeSpeechRequest; +import io.github.dsheirer.audio.convert.thumbdv.message.request.EncodeSpeechRequest; +import io.github.dsheirer.audio.convert.thumbdv.message.request.ResetRequest; +import io.github.dsheirer.audio.convert.thumbdv.message.request.SetVocoderParametersRequest; +import io.github.dsheirer.audio.convert.thumbdv.message.request.SetVocoderRequest; +import io.github.dsheirer.audio.convert.thumbdv.message.response.DecodeSpeechResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.ReadyResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.SetVocoderParameterResponse; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableAudioPacket; +import io.github.dsheirer.sample.buffer.ReusableAudioPacketQueue; +import io.github.dsheirer.util.ThreadPool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +/** + * Northwest Digital Radio (NWDR) ThumbDv dongle. + * + * Note: linux users must allow access to the serial port: + * + * sudo usermod -a -G uucp username + * sudo usermod -a -G dialout username + * sudo usermod -a -G lock username + * sudo usermod -a -G tty username + */ +public class ThumbDv implements AutoCloseable +{ + private final static Logger mLog = LoggerFactory.getLogger(ThumbDv.class); + private static final String PORT_DESCRIPTION = "USB-to-Serial Port (ftdi_sio)"; + private static final String PORT_DESCRIPTION_FRAGMENT = "USB Serial Port"; + private static final int BAUD_RATE = 460800; + private static final byte PACKET_START = (byte) 0x61; + + public enum AudioProtocol + { + DMR, + DSTAR, + NXDN, + P25_PHASE2, + } + + private SerialPort mSerialPort; + private ScheduledFuture mSerialPortReaderHandle; + private ScheduledFuture mAudioDecodeProcessorHandle; + private LinkedTransferQueue mDecodeSpeechRequests = new LinkedTransferQueue<>(); + private AudioProtocol mAudioProtocol; + private Listener mAudioPacketListener; + private ReusableAudioPacketQueue mReusableAudioPacketQueue = new ReusableAudioPacketQueue("ThumbDv"); + private boolean mStarted; + + public ThumbDv(AudioProtocol audioProtocol, Listener listener) + { + mAudioProtocol = audioProtocol; + mAudioPacketListener = listener; + } + + /** + * Enqueues the audio code frame for decoding. Decoded PCM speech packet will be sent to the registered + * audio packet listener. + * + * @param codecFrame + */ + public void decode(byte[] codecFrame) + { + if(!mStarted || mSerialPort == null) + { + throw new IllegalStateException("Must invoke start() method and thumbdv serial device must be available"); + } + + mDecodeSpeechRequests.offer(new DecodeSpeechRequest(codecFrame)); + } + + public void close() throws IOException + { + if(mSerialPortReaderHandle != null) + { + mSerialPortReaderHandle.cancel(true); + mSerialPortReaderHandle = null; + } + + if(mSerialPort != null) + { + mSerialPort.closePort(); + } + } + + public void start() throws IOException + { + if(mSerialPort == null) + { + SerialPort[] ports = SerialPort.getCommPorts(); + + for(SerialPort port : ports) + { + mLog.debug("Serial Port Name:" + port.getDescriptivePortName()); + if(port.getDescriptivePortName().contentEquals(PORT_DESCRIPTION) || + port.getDescriptivePortName().contains(PORT_DESCRIPTION_FRAGMENT)) + { + mSerialPort = port; + mSerialPort.setBaudRate(BAUD_RATE); + mSerialPort.openPort(0, 5000, 10000); + + if(mSerialPort.isOpen()) + { + mLog.info("Resetting ThumbDv Device"); + send(new ResetRequest()); + + mLog.info("Creating Serial Port Reader"); + final Runnable r = new SerialPortReader(mSerialPort.getInputStream()); + mLog.info("Starting Serial Port Reader"); + mSerialPortReaderHandle = ThreadPool.SCHEDULED.scheduleAtFixedRate(r, 0, + 5, TimeUnit.MILLISECONDS); + + mStarted = true; + mLog.info("Startup complete - awaiting reset response"); + } + else + { + mLog.warn("Could not open serial port: " + mSerialPort.getSystemPortName()); + throw new IOException("Could not open serial port:" + mSerialPort.getSystemPortName()); + } + + break; + } + } + } + + if(mSerialPort == null) + { + throw new IOException("ThumbDV serial port not found"); + } + + + return; + } + + public void send(byte[] message) throws IOException + { + if(mSerialPort == null) + { + throw new IOException("ThumbDv must be started before use"); + } + + int bytesWritten = mSerialPort.writeBytes(message, message.length); + + if(bytesWritten < 0) + { + throw new IOException("Unable to write message:" + Arrays.toString(message)); + } + else if(bytesWritten != message.length) + { + throw new IOException("Unable to write message:" + Arrays.toString(message) + " Bytes Written:" + bytesWritten); + } + } + + /** + * Sends the AMBE request message + * + * @param request message + * @throws IOException if there is an error + */ + public void send(AmbeRequest request) throws IOException + { + send(request.getData()); + } + + private void receive(byte[] bytes) + { + AmbeMessage message = AmbeMessageFactory.getMessage(bytes); + + if(message instanceof DecodeSpeechResponse && mAudioPacketListener != null) + { + float[] samples = ((DecodeSpeechResponse)message).getSamples(); + ReusableAudioPacket audioPacket = mReusableAudioPacketQueue.getBuffer(samples.length); + audioPacket.loadAudioFrom(samples); + mAudioPacketListener.receive(audioPacket); + } + else if(message instanceof ReadyResponse && mAudioDecodeProcessorHandle == null) + { + if(mAudioDecodeProcessorHandle == null) + { + try + { + switch(mAudioProtocol) + { + case DSTAR: + send(new SetVocoderRequest(VocoderRate.RATE_33)); + send(new SetVocoderParametersRequest(0x0130, 0x0763, 0x4000, 0x0000, 0x0000, 0x0048)); + break; + case DMR: + case NXDN: + case P25_PHASE2: + send(new SetVocoderRequest(VocoderRate.RATE_33)); + send(new SetVocoderParametersRequest(0x0431, 0x0754, 0x2400, 0x0000, 0x0000, 0x6F48)); + break; + default: + throw new IllegalStateException("Unrecognized audio protocol:" + mAudioProtocol); + } + } + catch(IOException ioe) + { + mLog.error("Error setting audio protocol vocoder parameters"); + } + + mLog.info("ThumbDv Reset Complete"); + } + else + { + mLog.info("ThumbDv Reset Detected"); + } + } + else if(message instanceof SetVocoderParameterResponse) + { + if(((SetVocoderParameterResponse)message).isSuccessful()) + { + mLog.info("Audio vocoder parameters configured for " + mAudioProtocol); + //Start the audio frame decode processor + mAudioDecodeProcessorHandle = ThreadPool.SCHEDULED.scheduleAtFixedRate(new AudioDecodeProcessor(), 0, + 10, TimeUnit.MILLISECONDS); + } + } + else if(message != null) + { + mLog.debug("RECEIVED:" + message.toString()); + } + } + + /** + * Logs the current settings of the serial port. Note: you must invoke start() before this method so that + * the serial port can be discovered and opened. + */ + public void logSerialPort() + { + if(mSerialPort != null) + { + StringBuilder sb = new StringBuilder(); + sb.append("\nPort:\t\t\t").append(mSerialPort.getSystemPortName()).append("\n"); + sb.append("Name:\t\t\t").append(mSerialPort.getDescriptivePortName()).append("\n"); + sb.append("Baud Rate:\t\t").append(mSerialPort.getBaudRate()).append("\n"); + sb.append("Data Bits:\t\t").append(mSerialPort.getNumDataBits()).append("\n"); + sb.append("Parity Bits:\t").append(mSerialPort.getParity()).append("\n"); + sb.append("Stop Bits:\t\t").append(mSerialPort.getNumStopBits()).append("\n"); + sb.append("Flow Control:\t").append(mSerialPort.getFlowControlSettings()).append("\n"); + sb.append("Is Open:\t\t").append(mSerialPort.isOpen()).append("\n"); + + mLog.info(sb.toString()); + } + else + { + mLog.info("No serial port found"); + } + } + + /** + * Processes the audio frame decode queue + */ + public class AudioDecodeProcessor implements Runnable + { + @Override + public void run() + { + try + { + DecodeSpeechRequest request = mDecodeSpeechRequests.poll(); + + if(request != null) + { + try + { + send(request); + } + catch(IOException ioe) + { + mLog.error("Error decoding audio frame", ioe); + } + +// try +// { +// //Force a 20ms sleep after submitting an audio frame to avoid overflowing the thumbdv +// Thread.sleep(20); +// } +// catch(InterruptedException ie) +// { +// //Do nothing +// } + } + } + catch(Throwable t) + { + mLog.error("Error", t); + } + } + } + + public class SerialPortReader implements Runnable + { + private InputStream mInputStream; + + public SerialPortReader(InputStream inputStream) + { + mInputStream = inputStream; + } + + @Override + public void run() + { + try + { + if(mInputStream != null) + { + try + { + while(mInputStream.available() > 0) + { + byte[] buffer = new byte[400]; + + int bytesRead = mInputStream.readNBytes(buffer, 0, 1); + + if(bytesRead == 1 && buffer[0] == PACKET_START) + { + while(mInputStream.available() < 2) + { + try + { + Thread.sleep(1); + } + catch(InterruptedException ie) + { + } + } + + bytesRead = mInputStream.readNBytes(buffer, 1, 2); + + if(bytesRead == 2) + { + int length = (0xFF & buffer[1]) << 8; + length += (0xFF & buffer[2]); + + if(0 < length && length < 400) + { + length++; //Add a byte for the type byte + + while(mInputStream.available() < length) + { + try + { + Thread.sleep(1); + } + catch(InterruptedException ie) + { + } + } + + bytesRead = mInputStream.readNBytes(buffer, 3, length); + + if(bytesRead == length) + { + receive(Arrays.copyOf(buffer, length + 3)); + } + else + { + mLog.debug("Expected [" + length + "] but received [" + bytesRead + "] bytes - " + Arrays.toString(buffer)); + } + } + else + { + mLog.error("Received packet with unexpected length: " + length); + //Don't process the buffer ... let the reader read and inspect 1 byte at a time + //to regain sync on the packet start byte + } + } + else + { + mLog.debug("Expected [2] but received [" + bytesRead + "] -- this shouldn't happen"); + } + } + else + { + mLog.debug("Unrecognized byte: " + Arrays.toString(buffer)); + } + } + } + catch(IOException ioe) + { + mLog.error("Error while reading ThumbDv serial port", ioe); + } + } + } + catch(Throwable t) + { + mLog.error("Error", t); + } + } + } + + public static void main(String[] args) + { + mLog.debug("Starting"); + + String silence = "BEDDEA821EFD660C08"; + + String[] frames = {"0E46122323067C60F8", "0E469433C1067CF1BC", "0E46122B23067C60F8", "0E67162BE08874E2B4", + "0E46163BE1067CF1BC", "0E46122B23067C60F8", "0A06163BE00A5C303E", "0E46122B23067C60F8", "0E46163BE1847CE1FC", + "0E46122B23067C60F8"}; + + List frameData = new ArrayList<>(); + + for(String frame : frames) + { + byte[] bytes = new byte[frame.length() / 2]; + for(int x = 0; x < frame.length(); x += 2) + { + String hex = frame.substring(x, x + 2); + bytes[x / 2] = (byte) (0xFF & Integer.parseInt(hex, 16)); + } + + frameData.add(bytes); + } + + mLog.debug("Starting thumb dv thread(s)"); + + final Listener listener = reusableAudioPacket -> { + mLog.info("Got an audio packet!"); + reusableAudioPacket.decrementUserCount(); + }; + + try(ThumbDv thumbDv = new ThumbDv(AudioProtocol.P25_PHASE2, listener)) + { + thumbDv.start(); + + Thread.sleep(6000); + + for(int x = 0; x < 20; x++) + { + thumbDv.send(new EncodeSpeechRequest(new short[160])); + Thread.sleep(20); + } +// for(byte[] frame : frameData) +// { +// thumbDv.decode(frame); +// } + + while(true); + } + catch(IOException ioe) + { + mLog.error("Error", ioe); + } + catch(InterruptedException e) + { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/AmbeMessage.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/AmbeMessage.java new file mode 100644 index 000000000..2df75085b --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/AmbeMessage.java @@ -0,0 +1,44 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message; + +/** + * AMBE-3000R Message + */ +public abstract class AmbeMessage +{ + /** + * Converts the byte array to a hexadecimal string array + */ + public static String toHex(byte[] data) + { + StringBuilder sb = new StringBuilder(); + + for(byte b: data) + { + sb.append(String.format("%02X", b)); + } + + return sb.toString(); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/AmbeMessageFactory.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/AmbeMessageFactory.java new file mode 100644 index 000000000..0cf9acfc3 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/AmbeMessageFactory.java @@ -0,0 +1,95 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message; + +import io.github.dsheirer.audio.convert.thumbdv.message.response.DecodeSpeechResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.EncodeSpeechResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.GetConfigResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.InitializeCodecResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.ProductIdResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.ReadyResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.SetChannelFormatResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.SetChannelResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.SetPacketModeResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.SetSpeechFormatResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.SetVocoderParameterResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.SetVocoderResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.UnknownResponse; +import io.github.dsheirer.audio.convert.thumbdv.message.response.VersionResponse; + +public class AmbeMessageFactory +{ + private static final byte CONTROL_PACKET = (byte)0x00; + private static final byte CHANNEL_PACKET = (byte)0x01; + private static final byte SPEECH_PACKET = (byte)0x02; + private static final int INDEX_PACKET_TYPE = 3; + private static final int INDEX_CONTROL_PACKET_TYPE = 4; + + + public static AmbeMessage getMessage(byte[] data) + { + if(data != null && data.length >= 5) + { + if(data[INDEX_PACKET_TYPE] == CONTROL_PACKET) + { + PacketField packetField = PacketField.fromValue(data[INDEX_CONTROL_PACKET_TYPE]); + + switch(packetField) + { + case PKT_CHANNEL_0: + return new SetChannelResponse(data); + case PKT_CHANNEL_FORMAT: + return new SetChannelFormatResponse(data); + case PKT_CODEC_STOP: + return new SetPacketModeResponse(data); + case PKT_GET_CONFIG: + return new GetConfigResponse(data); + case PKT_INIT: + return new InitializeCodecResponse(data); + case PKT_PRODUCT_ID: + return new ProductIdResponse(data); + case PKT_RATE_PARAMETER: + return new SetVocoderParameterResponse(data); + case PKT_RATE_TABLE: + return new SetVocoderResponse(data); + case PKT_READY: + return new ReadyResponse(data); + case PKT_SPEECH_FORMAT: + return new SetSpeechFormatResponse(data); + case PKT_VERSION_STRING: + return new VersionResponse(data); + } + } + else if(data[INDEX_PACKET_TYPE] == CHANNEL_PACKET) + { + return new EncodeSpeechResponse(data); + } + else if(data[INDEX_PACKET_TYPE] == SPEECH_PACKET) + { + return new DecodeSpeechResponse(data); + } + } + + return new UnknownResponse(data); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/InitializeOption.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/InitializeOption.java new file mode 100644 index 000000000..bc60ff7aa --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/InitializeOption.java @@ -0,0 +1,47 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message; + +/** + * AMBE-3000 Initialization Options + */ +public enum InitializeOption +{ + ENCODER((byte)0x01), + DECODER((byte)0x02), + ENCODER_AND_DECODER((byte)0x03), + ECHO_CANCELLER((byte)0x04), + ENCODER_DECODER_ECHO_CANCELLER((byte)0x07); + + private byte mCode; + + InitializeOption(byte code) + { + mCode = code; + } + + public byte getCode() + { + return mCode; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/PacketField.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/PacketField.java new file mode 100644 index 000000000..1b15f9933 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/PacketField.java @@ -0,0 +1,163 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message; + +/** + * AMBE-3000R Control Packet Field enumeration + */ +public enum PacketField +{ + PKT_ENCODER_CMODE((byte)0x05), + PKT_DECODER_CMODE((byte)0x06), + PKT_RATE_TABLE((byte)0x09), + PKT_RATE_PARAMETER((byte)0x0A), + PKT_INIT((byte)0x0B), + PKT_LOW_POWER((byte)0x10), + PKT_CHANNEL_FORMAT((byte)0x15), + PKT_SPEECH_FORMAT((byte)0x16), + PKT_CODEC_START((byte)0x2A), + PKT_CODEC_STOP((byte)0x2B), + PKT_PRODUCT_ID((byte)0x30), + PKT_VERSION_STRING((byte)0x31), + PKT_COMPAND((byte)0x32), + PKT_RESET((byte)0x33), + PKT_RESET_TO_SOFTWARE_CONFIG((byte)0x34), + PKT_HALT((byte)0x35), + PKT_GET_CONFIG((byte)0x36), + PKT_READ_CONFIG((byte)0x37), + PKT_CODEC_CFG((byte)0x38), + PKT_READY((byte)0x39), + PKT_PARITY_MODE((byte)0x3F), + PKT_CHANNEL_0((byte)0x40), + PKT_WRITE_I2C((byte)0x44), + PKT_CLEAR_CODEC_RESET((byte)0x46), + PKT_SET_CODEC_RESET((byte)0x47), + PKT_DISCARD_CODEC_SAMPLES((byte)0x48), + PKT_DELAY_NUMBER_MICRO_SECONDS((byte)0x49), + PKT_DELAY_NUMBER_NANO_SECONDS((byte)0x4A), + PKT_GAIN((byte)0x4B), + PKT_RTS_THRESHOLD((byte)0x4E), + + //Speech packet values + SPEECH_DATA((byte)0x00), + CHANNEL_DATA_HARD_SYMBOL((byte)0x01), + CMODE((byte)0x02), + SAMPLE_COUNT((byte)0x03), + TONE((byte)0x08), + CHANNEL_DATA_SOFT_SYMBOL((byte)0x17), + VOCODER((byte)0x40), + + //Packet Types + PACKET_TYPE_CONTROL((byte)0x00), + PACKET_TYPE_ENCODE_SPEECH((byte)0x01), + PACKET_TYPE_DECODE_SPEECH((byte)0x02), + + UNKNOWN((byte)0x00); + + private byte mCode; + + PacketField(byte code) + { + mCode = code; + } + + /** + * Packet type byte code value + */ + public byte getCode() + { + return mCode; + } + + /** + * Lookup a packet type from the code byte value + */ + public static PacketField fromValue(byte value) + { + switch(value) + { + case (byte)0x05: + return PKT_ENCODER_CMODE; + case (byte)0x06: + return PKT_DECODER_CMODE; + case (byte)0x09: + return PKT_RATE_TABLE; + case (byte)0x0A: + return PKT_RATE_PARAMETER; + case (byte)0x0B: + return PKT_INIT; + case (byte)0x10: + return PKT_LOW_POWER; + case (byte)0x15: + return PKT_CHANNEL_FORMAT; + case (byte)0x16: + return PKT_SPEECH_FORMAT; + case (byte)0x2A: + return PKT_CODEC_START; + case (byte)0x2B: + return PKT_CODEC_STOP; + case (byte)0x30: + return PKT_PRODUCT_ID; + case (byte)0x31: + return PKT_VERSION_STRING; + case (byte)0x32: + return PKT_COMPAND; + case (byte)0x33: + return PKT_RESET; + case (byte)0x34: + return PKT_RESET_TO_SOFTWARE_CONFIG; + case (byte)0x35: + return PKT_HALT; + case (byte)0x36: + return PKT_GET_CONFIG; + case (byte)0x37: + return PKT_READ_CONFIG; + case (byte)0x38: + return PKT_CODEC_CFG; + case (byte)0x39: + return PKT_READY; + case (byte)0x3F: + return PKT_PARITY_MODE; + case (byte)0x40: + return PKT_CHANNEL_0; + case (byte)0x44: + return PKT_WRITE_I2C; + case (byte)0x46: + return PKT_CLEAR_CODEC_RESET; + case (byte)0x47: + return PKT_SET_CODEC_RESET; + case (byte)0x48: + return PKT_DISCARD_CODEC_SAMPLES; + case (byte)0x49: + return PKT_DELAY_NUMBER_MICRO_SECONDS; + case (byte)0x4A: + return PKT_DELAY_NUMBER_NANO_SECONDS; + case (byte)0x4B: + return PKT_GAIN; + case (byte)0x4E: + return PKT_RTS_THRESHOLD; + default: + return UNKNOWN; + } + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/VocoderRate.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/VocoderRate.java new file mode 100644 index 000000000..cd986e4bf --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/VocoderRate.java @@ -0,0 +1,129 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message; + +public enum VocoderRate +{ + //AMBE-1000 Standard Rates + RATE_0((byte)0x00, 2400,0), + RATE_1((byte)0x01, 3600,0), + RATE_2((byte)0x02, 3600,1200), + RATE_3((byte)0x03, 4800,0), + RATE_4((byte)0x04, 9600,0), + RATE_5((byte)0x05, 2350,50), + RATE_6((byte)0x06, 4850,4750), + RATE_7((byte)0x07, 4550,250), + RATE_8((byte)0x08, 3100,1700), + RATE_9((byte)0x09, 4400,2800), + RATE_10((byte)0x0A, 4150,2250), + RATE_11((byte)0x0B, 3350,250), + RATE_12((byte)0x0C, 7750,250), + RATE_13((byte)0x0D, 4650,3350), + RATE_14((byte)0x0E, 3750,250), + RATE_15((byte)0x0F, 4000,0), + + //AMBE-2000 Standard Rates + RATE_16((byte)0x10, 3600,0), + RATE_17((byte)0x11, 4000,0), + RATE_18((byte)0x12, 4800,0), + RATE_19((byte)0x13, 6400,0), + RATE_20((byte)0x14, 8000,0), + RATE_21((byte)0x15, 9600,0), + RATE_22((byte)0x16, 2400,1600), + RATE_23((byte)0x17, 3600,1200), + RATE_24((byte)0x18, 4000,800), + RATE_25((byte)0x19, 2400,2400), + RATE_26((byte)0x1A, 4000,2400), + RATE_27((byte)0x1B, 4400,2800), //Is this compatible with APCO25 Phase 1? + RATE_28((byte)0x1C, 4000,4000), + RATE_29((byte)0x1D, 2400,7200), + RATE_30((byte)0x1E, 3600,6000), + RATE_31((byte)0x1F, 2000,0), + RATE_32((byte)0x20, 3600,2800), + + //AMBE-3000 Standard Rates (AMBE+2) + RATE_33((byte)0x21, 2450,1150), //APCO25 HR (Phase 2), DMR, NXDN, DSTAR + RATE_34((byte)0x22, 2450,0), + RATE_35((byte)0x23, 2250,1150), + RATE_36((byte)0x24, 2250,0), + RATE_37((byte)0x25, 2400,0), + RATE_38((byte)0x26, 3000,0), + RATE_39((byte)0x27, 3600,0), + RATE_40((byte)0x28, 4000,0), + RATE_41((byte)0x29, 4400,0), + RATE_42((byte)0x2A, 4800,0), + RATE_43((byte)0x2B, 6400,0), + RATE_44((byte)0x2C, 7200,0), + RATE_45((byte)0x2D, 8000,0), + RATE_46((byte)0x2E, 9600,0), + RATE_47((byte)0x2F, 2450,250), + RATE_48((byte)0x30, 3350,250), + RATE_49((byte)0x31, 3750,250), + RATE_50((byte)0x32, 4550,250), + RATE_51((byte)0x33, 2450,1950), + RATE_52((byte)0x34, 2450,2350), + RATE_53((byte)0x35, 2450,3550), + RATE_54((byte)0x36, 2450,4750), + RATE_55((byte)0x37, 2600,1400), + RATE_56((byte)0x38, 3600,1200), + RATE_57((byte)0x39, 4000,800), + RATE_58((byte)0x3A, 4000,2400), + RATE_59((byte)0x3B, 4400,2800), //Is this compatible with APCO25 Phase 1? + RATE_60((byte)0x3C, 4000,4000), + RATE_61((byte)0x3D, 3600,6000); + + private byte mCode; + private int mSpeechRate; + private int mFecRate; + + VocoderRate(byte code, int speechRate, int fecRate) + { + mCode = code; + mSpeechRate = speechRate; + mFecRate = fecRate; + } + + /** + * Byte code value for the vocoder rate + */ + public byte getCode() + { + return mCode; + } + + /** + * Speech rate in bits per second (bps) + */ + public int getSpeechRate() + { + return mSpeechRate; + } + + /** + * Forward Error Correction rate in bits per second (bps) + */ + public int getFecRate() + { + return mFecRate; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/AmbeRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/AmbeRequest.java new file mode 100644 index 000000000..cab855921 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/AmbeRequest.java @@ -0,0 +1,67 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.AmbeMessage; +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * AMBE-3000R Request Packet + */ +public abstract class AmbeRequest extends AmbeMessage +{ + private static final byte PACKET_START_BYTE = (byte)0x61; + protected static final int PACKET_TYPE_INDEX = 3; + protected static final int PAYLOAD_START_INDEX = 4; + + public abstract PacketField getType(); + public abstract byte[] getData(); + + /** + * Creates a byte array of the specified length plus 4 packet header bytes with packet start, length and control + * bytes filled in. + * + * @param length of the message (not including the 4 byte packet header) + * @return byte array with packet header pre-filled. + */ + protected byte[] createMessage(int length, PacketField type) + { + byte[] data = new byte[length + 4]; + + data[0] = PACKET_START_BYTE; + data[1] = (byte)((length >> 8 & 0xFF)); + data[2] = (byte)(length & 0xFF); + + if(type == PacketField.PACKET_TYPE_ENCODE_SPEECH || type == PacketField.PACKET_TYPE_DECODE_SPEECH) + { + data[PACKET_TYPE_INDEX] = type.getCode(); + } + else + { + data[PACKET_TYPE_INDEX] = PacketField.PACKET_TYPE_CONTROL.getCode(); + data[PAYLOAD_START_INDEX] = type.getCode(); + } + + return data; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/DecodeSpeechRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/DecodeSpeechRequest.java new file mode 100644 index 000000000..0ec12fa5c --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/DecodeSpeechRequest.java @@ -0,0 +1,108 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; +import io.github.dsheirer.audio.convert.thumbdv.message.VocoderRate; + +/** + * Decode speech request, used to request decode of an encoded audio frame. + */ +public class DecodeSpeechRequest extends AmbeRequest +{ + private static final int CHANNEL_DATA_IDENTIFIER_INDEX = 4; + private static final byte SAMPLE_COUNT = (byte)(0xFF & 160); //8 kHz Audio sample count for 20ms frame + + private byte[] mAudioFrame; + private VocoderRate mVocoderRate; + + /** + * Constructs an audio frame decode request using the specified vocoder rate. + * @param audioFrame of encoded audio samples + * @param vocoderRate to use when decoding + */ + public DecodeSpeechRequest(byte[] audioFrame, VocoderRate vocoderRate) + { + mAudioFrame = audioFrame; + mVocoderRate = vocoderRate; + } + + /** + * Constructs an audio frame decode request using the current vocoder rate. + * @param audioFrame of encoded audio samples + */ + public DecodeSpeechRequest(byte[] audioFrame) + { + this(audioFrame, null); + } + + @Override + public PacketField getType() + { + return PacketField.PACKET_TYPE_ENCODE_SPEECH; + } + + private boolean hasVocoderRate() + { + return mVocoderRate != null; + } + + @Override + public byte[] getData() + { + if(hasVocoderRate()) + { + int length = mAudioFrame.length + 9; + + byte[] data = createMessage(length, getType()); + int offset = CHANNEL_DATA_IDENTIFIER_INDEX; + + data[offset++] = PacketField.VOCODER.getCode(); + data[offset++] = mVocoderRate.getCode(); + + data[offset++] = PacketField.CHANNEL_DATA_HARD_SYMBOL.getCode(); + data[offset++] = (byte)(0xFF & (mAudioFrame.length * 8)); + System.arraycopy(mAudioFrame, 0, data, offset, mAudioFrame.length); + offset += mAudioFrame.length; + data[offset++] = PacketField.SAMPLE_COUNT.getCode(); + data[offset++] = (byte)0xA0; + data[offset++] = (byte)0x02; + data[offset++] = (byte)0x00; + data[offset] = (byte)0x00; + + return data; + } + else + { + int length = mAudioFrame.length + 2; + byte[] data = createMessage(length, getType()); + + int offset = CHANNEL_DATA_IDENTIFIER_INDEX; + data[offset++] = PacketField.CHANNEL_DATA_HARD_SYMBOL.getCode(); + data[offset++] = (byte)(0xFF & (mAudioFrame.length * 8)); + System.arraycopy(mAudioFrame, 0, data, offset, mAudioFrame.length); + + return data; + } + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/EncodeSpeechRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/EncodeSpeechRequest.java new file mode 100644 index 000000000..2c826014a --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/EncodeSpeechRequest.java @@ -0,0 +1,88 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +public class EncodeSpeechRequest extends AmbeRequest +{ + private static final int CHANNEL_IDENTIFIER_INDEX = 4; + private static final int SPEECH_DATA_IDENTIFIER_INDEX = 5; + private static final int SAMPLE_COUNT_INDEX = 6; + private static final int SPEECH_DATA_START_INDEX = 7; + + private short[] mSamples; + + public EncodeSpeechRequest(short[] samples) + { + mSamples = samples; + } + + public EncodeSpeechRequest(float[] samples) + { + mSamples = new short[samples.length]; + + for(int x = 0; x < samples.length; x++) + { + if(samples[x] > 1.0f) + { + mSamples[x] = Short.MAX_VALUE; + } + else if(samples[x] < -1.0f) + { + mSamples[x] = Short.MIN_VALUE; + } + else + { + mSamples[x] = (short)(samples[x] * Short.MAX_VALUE); + } + } + } + + @Override + public PacketField getType() + { + return PacketField.PACKET_TYPE_DECODE_SPEECH; + } + + @Override + public byte[] getData() + { + int length = (mSamples.length * 2) + 3; + byte[] data = createMessage(length, getType()); + + data[CHANNEL_IDENTIFIER_INDEX] = PacketField.PKT_CHANNEL_0.getCode(); + data[SPEECH_DATA_IDENTIFIER_INDEX] = (byte)0x00; + data[SAMPLE_COUNT_INDEX] = (byte)(0xFF & mSamples.length); + + int pointer = SPEECH_DATA_START_INDEX; + + for(short sample: mSamples) + { + data[pointer++] = (byte)((sample >> 8 & 0xFF)); + data[pointer++] = (byte)(sample & 0xFF); + } + + return data; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/GetConfigRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/GetConfigRequest.java new file mode 100644 index 000000000..a6c7227a1 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/GetConfigRequest.java @@ -0,0 +1,43 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Get configuration request packet + */ +public class GetConfigRequest extends AmbeRequest +{ + @Override + public PacketField getType() + { + return PacketField.PKT_GET_CONFIG; + } + + @Override + public byte[] getData() + { + return createMessage(1, getType()); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/InitializeCodecRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/InitializeCodecRequest.java new file mode 100644 index 000000000..1737d404e --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/InitializeCodecRequest.java @@ -0,0 +1,54 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.InitializeOption; +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Initialize CODEC request packet + */ +public class InitializeCodecRequest extends AmbeRequest +{ + private static final int INITIALIZE_OPTION_INDEX = 5; + private InitializeOption mInitializeOption; + + public InitializeCodecRequest(InitializeOption option) + { + mInitializeOption = option; + } + + @Override + public PacketField getType() + { + return PacketField.PKT_INIT; + } + + @Override + public byte[] getData() + { + byte[] data = createMessage(2, getType()); + data[INITIALIZE_OPTION_INDEX] = mInitializeOption.getCode(); + return data; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/ProductIdRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/ProductIdRequest.java new file mode 100644 index 000000000..fe7969fff --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/ProductIdRequest.java @@ -0,0 +1,43 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Product ID request packet + */ +public class ProductIdRequest extends AmbeRequest +{ + @Override + public PacketField getType() + { + return PacketField.PKT_PRODUCT_ID; + } + + @Override + public byte[] getData() + { + return createMessage(1, getType()); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/ResetRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/ResetRequest.java new file mode 100644 index 000000000..4ae89073a --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/ResetRequest.java @@ -0,0 +1,43 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Reset request packet + */ +public class ResetRequest extends AmbeRequest +{ + @Override + public PacketField getType() + { + return PacketField.PKT_RESET; + } + + @Override + public byte[] getData() + { + return createMessage(1, getType()); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetChannelFormatRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetChannelFormatRequest.java new file mode 100644 index 000000000..4326e615a --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetChannelFormatRequest.java @@ -0,0 +1,48 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Set channel format request packet + */ +public class SetChannelFormatRequest extends AmbeRequest +{ + private static final int FORMAT_INDEX = 5; + private static final byte FORMAT = (byte)0x00; + + @Override + public PacketField getType() + { + return PacketField.PKT_CHANNEL_FORMAT; + } + + @Override + public byte[] getData() + { + byte[] data = createMessage(2, getType()); + data[FORMAT_INDEX] = FORMAT; + return data; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetChannelRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetChannelRequest.java new file mode 100644 index 000000000..b8ea0fef4 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetChannelRequest.java @@ -0,0 +1,43 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Set channel request packet + */ +public class SetChannelRequest extends AmbeRequest +{ + @Override + public PacketField getType() + { + return PacketField.PKT_CHANNEL_0; + } + + @Override + public byte[] getData() + { + return createMessage(1, getType()); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetPacketModeRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetPacketModeRequest.java new file mode 100644 index 000000000..ca8a52b3d --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetPacketModeRequest.java @@ -0,0 +1,43 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Packet mode (versus CODEC mode) request packet + */ +public class SetPacketModeRequest extends AmbeRequest +{ + @Override + public PacketField getType() + { + return PacketField.PKT_CODEC_STOP; + } + + @Override + public byte[] getData() + { + return createMessage(1, getType()); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetSpeechFormatRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetSpeechFormatRequest.java new file mode 100644 index 000000000..8ebcbbbb0 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetSpeechFormatRequest.java @@ -0,0 +1,48 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Set speech format request packet + */ +public class SetSpeechFormatRequest extends AmbeRequest +{ + private static final int FORMAT_INDEX = 5; + private static final byte FORMAT = (byte)0x00; + + @Override + public PacketField getType() + { + return PacketField.PKT_SPEECH_FORMAT; + } + + @Override + public byte[] getData() + { + byte[] data = createMessage(2, getType()); + data[FORMAT_INDEX] = FORMAT; + return data; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetVocoderParametersRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetVocoderParametersRequest.java new file mode 100644 index 000000000..ba980284b --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetVocoderParametersRequest.java @@ -0,0 +1,74 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Set Vocoder parameters request packet + */ +public class SetVocoderParametersRequest extends AmbeRequest +{ + private int mWord0; + private int mWord1; + private int mWord2; + private int mWord3; + private int mWord4; + private int mWord5; + + public SetVocoderParametersRequest(int word0, int word1, int word2, int word3, int word4, int word5) + { + mWord0 = word0; + mWord1 = word1; + mWord2 = word2; + mWord3 = word3; + mWord4 = word4; + mWord5 = word5; + } + + @Override + public PacketField getType() + { + return PacketField.PKT_RATE_PARAMETER; + } + + @Override + public byte[] getData() + { + byte[] data = createMessage(14, getType()); + data[PAYLOAD_START_INDEX + 1] = (byte)(mWord0 >> 8 & 0xFF); + data[PAYLOAD_START_INDEX + 2] = (byte)(mWord0 & 0xFF); + data[PAYLOAD_START_INDEX + 3] = (byte)(mWord1 >> 8 & 0xFF); + data[PAYLOAD_START_INDEX + 4] = (byte)(mWord1 & 0xFF); + data[PAYLOAD_START_INDEX + 5] = (byte)(mWord2 >> 8 & 0xFF); + data[PAYLOAD_START_INDEX + 6] = (byte)(mWord2 & 0xFF); + data[PAYLOAD_START_INDEX + 7] = (byte)(mWord3 >> 8 & 0xFF); + data[PAYLOAD_START_INDEX + 8] = (byte)(mWord3 & 0xFF); + data[PAYLOAD_START_INDEX + 9] = (byte)(mWord4 >> 8 & 0xFF); + data[PAYLOAD_START_INDEX + 10] = (byte)(mWord4 & 0xFF); + data[PAYLOAD_START_INDEX + 11] = (byte)(mWord5 >> 8 & 0xFF); + data[PAYLOAD_START_INDEX + 12] = (byte)(mWord5 & 0xFF); + + return data; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetVocoderRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetVocoderRequest.java new file mode 100644 index 000000000..c39d5cd16 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/SetVocoderRequest.java @@ -0,0 +1,53 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; +import io.github.dsheirer.audio.convert.thumbdv.message.VocoderRate; + +/** + * Set Vocoder Rate request packet + */ +public class SetVocoderRequest extends AmbeRequest +{ + private VocoderRate mVocoderRate; + + public SetVocoderRequest(VocoderRate rate) + { + mVocoderRate = rate; + } + + @Override + public PacketField getType() + { + return PacketField.PKT_RATE_TABLE; + } + + @Override + public byte[] getData() + { + byte[] data = createMessage(2, getType()); + data[PAYLOAD_START_INDEX + 1] = mVocoderRate.getCode(); + return data; + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/VersionRequest.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/VersionRequest.java new file mode 100644 index 000000000..fa2d78beb --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/request/VersionRequest.java @@ -0,0 +1,43 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.request; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Version string request packet + */ +public class VersionRequest extends AmbeRequest +{ + @Override + public PacketField getType() + { + return PacketField.PKT_VERSION_STRING; + } + + @Override + public byte[] getData() + { + return createMessage(1, getType()); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/AmbeResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/AmbeResponse.java new file mode 100644 index 000000000..b51836984 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/AmbeResponse.java @@ -0,0 +1,63 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.AmbeMessage; +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +import java.util.Arrays; + +/** + * AMBE-3000R Response Packet + */ +public abstract class AmbeResponse extends AmbeMessage +{ + protected static final int PAYLOAD_START_INDEX = 5; + private byte[] mMessage; + + protected AmbeResponse(byte[] message) + { + mMessage = message; + } + + /** + * Control packet type + */ + public abstract PacketField getType(); + + /** + * Received message bytes + */ + protected byte[] getMessage() + { + return mMessage; + } + + /** + * Payload of the packet (does not include the packet header) + */ + protected byte[] getPayload() + { + return Arrays.copyOfRange(getMessage(), PAYLOAD_START_INDEX, getMessage().length); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/DecodeSpeechResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/DecodeSpeechResponse.java new file mode 100644 index 000000000..44b6f191e --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/DecodeSpeechResponse.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * sdr-trunk + * 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 + * + ******************************************************************************/ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; +import io.github.dsheirer.sample.ConversionUtils; + +import java.util.Arrays; + +/** + * Decode speech response + */ +public class DecodeSpeechResponse extends AmbeResponse +{ + public DecodeSpeechResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PACKET_TYPE_DECODE_SPEECH; + } + + + /** + * Payload of the packet (does not include the packet header) + */ + protected byte[] getPayload() + { + return Arrays.copyOfRange(getMessage(), PAYLOAD_START_INDEX + 1, getMessage().length); + } + + public float[] getSamples() + { + return ConversionUtils.convertFromSigned16BitSamples(getPayload()); + } + + @Override + public String toString() + { + return "DECODED SPEECH: SAMPLE COUNT:" + getSamples().length + " " + toHex(getPayload()); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/EncodeSpeechResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/EncodeSpeechResponse.java new file mode 100644 index 000000000..d86de460d --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/EncodeSpeechResponse.java @@ -0,0 +1,59 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +import java.util.Arrays; + +/** + * Encode speech response + */ +public class EncodeSpeechResponse extends AmbeResponse +{ + public EncodeSpeechResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PACKET_TYPE_ENCODE_SPEECH; + } + + + /** + * Payload of the packet (does not include the packet header) + */ + protected byte[] getPayload() + { + return Arrays.copyOfRange(getMessage(), PAYLOAD_START_INDEX + 1, getMessage().length); + } + + @Override + public String toString() + { + return "ENCODED SPEECH: " + toHex(getPayload()) + " " + Arrays.toString(getMessage()); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/GetConfigResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/GetConfigResponse.java new file mode 100644 index 000000000..fda9f31e0 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/GetConfigResponse.java @@ -0,0 +1,49 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Get configuration response + */ +public class GetConfigResponse extends AmbeResponse +{ + public GetConfigResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PKT_GET_CONFIG; + } + + + @Override + public String toString() + { + return "CONFIGURATION: " + toHex(getPayload()); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/InitializeCodecResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/InitializeCodecResponse.java new file mode 100644 index 000000000..e661ecf73 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/InitializeCodecResponse.java @@ -0,0 +1,58 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Initialize CODEC response + */ +public class InitializeCodecResponse extends AmbeResponse +{ + public InitializeCodecResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PKT_INIT; + } + + /** + * Success / fail + */ + public boolean isSuccessful() + { + byte[] payload = getPayload(); + + return payload != null && payload.length ==1 && payload[0] == 0; + } + + @Override + public String toString() + { + return "INITIALIZE CODEC " + (isSuccessful() ? "SUCCESSFUL" : "**FAILED**"); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/ProductIdResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/ProductIdResponse.java new file mode 100644 index 000000000..98f1e8768 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/ProductIdResponse.java @@ -0,0 +1,56 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Product ID Response + */ +public class ProductIdResponse extends AmbeResponse +{ + public ProductIdResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PKT_PRODUCT_ID; + } + + /** + * Product ID string + */ + public String getProductId() + { + return new String(getPayload()).trim(); + } + + @Override + public String toString() + { + return "PRODUCT ID:" + getProductId(); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/ReadyResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/ReadyResponse.java new file mode 100644 index 000000000..e979b422c --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/ReadyResponse.java @@ -0,0 +1,50 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +import java.util.Arrays; + +/** + * Ready response + */ +public class ReadyResponse extends AmbeResponse +{ + public ReadyResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PKT_READY; + } + + @Override + public String toString() + { + return "READY" + Arrays.toString(getMessage()); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/ResetResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/ResetResponse.java new file mode 100644 index 000000000..c76a688d1 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/ResetResponse.java @@ -0,0 +1,57 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Reset response + */ +public class ResetResponse extends AmbeResponse +{ + public ResetResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PKT_RESET; + } + + /** + * Success indicator + */ + public boolean isSuccessful() + { + byte[] payload = getPayload(); + return payload != null && payload.length ==1 && payload[0] == 0; + } + + @Override + public String toString() + { + return "RESET " + (isSuccessful() ? "SUCCESSFUL" : "**FAILED**"); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetChannelFormatResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetChannelFormatResponse.java new file mode 100644 index 000000000..e7e5ae81e --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetChannelFormatResponse.java @@ -0,0 +1,58 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Set channel format response + */ +public class SetChannelFormatResponse extends AmbeResponse +{ + public SetChannelFormatResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PKT_CHANNEL_FORMAT; + } + + /** + * Success or fail + */ + public boolean isSuccessful() + { + byte[] payload = getPayload(); + + return payload != null && payload.length ==1 && payload[0] == 0; + } + + @Override + public String toString() + { + return "SET CHANNEL FORMAT " + (isSuccessful() ? "SUCCESSFUL" : "**FAILED**"); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetChannelResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetChannelResponse.java new file mode 100644 index 000000000..509de3f03 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetChannelResponse.java @@ -0,0 +1,57 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Set Vocoder rate response + */ +public class SetChannelResponse extends AmbeResponse +{ + public SetChannelResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PKT_CHANNEL_0; + } + + /** + * Success indicator + */ + public boolean isSuccessful() + { + byte[] payload = getPayload(); + return payload != null && payload.length ==1 && payload[0] == 0; + } + + @Override + public String toString() + { + return "SET CHANNEL 0 " + (isSuccessful() ? "SUCCESSFUL" : "**FAILED**"); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetPacketModeResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetPacketModeResponse.java new file mode 100644 index 000000000..04b04c5e2 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetPacketModeResponse.java @@ -0,0 +1,58 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Set packet mode response + */ +public class SetPacketModeResponse extends AmbeResponse +{ + public SetPacketModeResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PKT_CODEC_STOP; + } + + /** + * Success or fail + */ + public boolean isSuccessful() + { + byte[] payload = getPayload(); + + return payload != null && payload.length ==1 && payload[0] == 0; + } + + @Override + public String toString() + { + return "SET PACKET MODE " + (isSuccessful() ? "SUCCESSFUL" : "**FAILED**"); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetSpeechFormatResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetSpeechFormatResponse.java new file mode 100644 index 000000000..dae8b3589 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetSpeechFormatResponse.java @@ -0,0 +1,58 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Set speech format response + */ +public class SetSpeechFormatResponse extends AmbeResponse +{ + public SetSpeechFormatResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PKT_SPEECH_FORMAT; + } + + /** + * Success or fail + */ + public boolean isSuccessful() + { + byte[] payload = getPayload(); + + return payload != null && payload.length ==1 && payload[0] == 0; + } + + @Override + public String toString() + { + return "SET SPEECH FORMAT " + (isSuccessful() ? "SUCCESSFUL" : "**FAILED**"); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetVocoderParameterResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetVocoderParameterResponse.java new file mode 100644 index 000000000..6d5dd05ad --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetVocoderParameterResponse.java @@ -0,0 +1,65 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Set Vocoder parameter response + */ +public class SetVocoderParameterResponse extends AmbeResponse +{ + public SetVocoderParameterResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PKT_RATE_PARAMETER; + } + + /** + * Success indicator + */ + public boolean isSuccessful() + { + byte[] payload = getPayload(); + + return payload != null && payload.length ==3 && payload[0] == 0; + } + + @Override + public String toString() + { + if(isSuccessful()) + { + return "SET VOCODER RATE SUCCESSFUL"; + } + else + { + return "SET VOCODER RATE **FAILED** - RESPONSE:" + toHex(getPayload()); + } + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetVocoderResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetVocoderResponse.java new file mode 100644 index 000000000..eb629c283 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/SetVocoderResponse.java @@ -0,0 +1,58 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Set Vocoder rate response + */ +public class SetVocoderResponse extends AmbeResponse +{ + public SetVocoderResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PKT_RATE_TABLE; + } + + /** + * Success indicator + */ + public boolean isSuccessful() + { + byte[] payload = getPayload(); + + return payload != null && payload.length ==1 && payload[0] == 0; + } + + @Override + public String toString() + { + return "SET VOCODER RATE " + (isSuccessful() ? "SUCCESSFUL" : "**FAILED**"); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/UnknownResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/UnknownResponse.java new file mode 100644 index 000000000..2a31e438a --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/UnknownResponse.java @@ -0,0 +1,50 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +import java.util.Arrays; + +/** + * Unknown Response Message + */ +public class UnknownResponse extends AmbeResponse +{ + public UnknownResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.UNKNOWN; + } + + @Override + public String toString() + { + return "UNKNOWN MESSAGE:" + Arrays.toString(getMessage()); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/VersionResponse.java b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/VersionResponse.java new file mode 100644 index 000000000..2522b9f27 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/convert/thumbdv/message/response/VersionResponse.java @@ -0,0 +1,56 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.convert.thumbdv.message.response; + +import io.github.dsheirer.audio.convert.thumbdv.message.PacketField; + +/** + * Version Response + */ +public class VersionResponse extends AmbeResponse +{ + public VersionResponse(byte[] message) + { + super(message); + } + + @Override + public PacketField getType() + { + return PacketField.PKT_VERSION_STRING; + } + + /** + * Version string + */ + public String getVersion() + { + return new String(getPayload()).trim(); + } + + @Override + public String toString() + { + return "VERSION:" + getVersion(); + } +} diff --git a/src/main/java/io/github/dsheirer/audio/playback/AudioOutput.java b/src/main/java/io/github/dsheirer/audio/playback/AudioOutput.java index db74594b9..f04c315a5 100644 --- a/src/main/java/io/github/dsheirer/audio/playback/AudioOutput.java +++ b/src/main/java/io/github/dsheirer/audio/playback/AudioOutput.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.audio.playback; @@ -54,7 +56,7 @@ public abstract class AudioOutput implements Listener, Line private LinkedTransferQueue mBuffer = new LinkedTransferQueue<>(); private int mBufferStartThreshold; private int mBufferStopThreshold; - private static IdentifierCollection EMPTY_IDENTIFIER_COLLECTION = new IdentifierCollection(); + private static IdentifierCollection EMPTY_IDENTIFIER_COLLECTION = new IdentifierCollection(0); static { EMPTY_IDENTIFIER_COLLECTION.setUpdated(true); diff --git a/src/main/java/io/github/dsheirer/audio/squelch/ISquelchStateListener.java b/src/main/java/io/github/dsheirer/audio/squelch/ISquelchStateListener.java index 0d7249a7b..1a3150e4b 100644 --- a/src/main/java/io/github/dsheirer/audio/squelch/ISquelchStateListener.java +++ b/src/main/java/io/github/dsheirer/audio/squelch/ISquelchStateListener.java @@ -1,8 +1,30 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + package io.github.dsheirer.audio.squelch; import io.github.dsheirer.sample.Listener; public interface ISquelchStateListener { - public Listener getSquelchStateListener(); + Listener getSquelchStateListener(); } diff --git a/src/main/java/io/github/dsheirer/audio/squelch/ISquelchStateProvider.java b/src/main/java/io/github/dsheirer/audio/squelch/ISquelchStateProvider.java index 908dad7a2..7bcff40cb 100644 --- a/src/main/java/io/github/dsheirer/audio/squelch/ISquelchStateProvider.java +++ b/src/main/java/io/github/dsheirer/audio/squelch/ISquelchStateProvider.java @@ -1,9 +1,32 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + package io.github.dsheirer.audio.squelch; import io.github.dsheirer.sample.Listener; public interface ISquelchStateProvider { - public void setSquelchStateListener( Listener listener ); - public void removeSquelchStateListener(); + void setSquelchStateListener(Listener listener); + + void removeSquelchStateListener(); } diff --git a/src/main/java/io/github/dsheirer/audio/squelch/SquelchStateEvent.java b/src/main/java/io/github/dsheirer/audio/squelch/SquelchStateEvent.java new file mode 100644 index 000000000..e96c62843 --- /dev/null +++ b/src/main/java/io/github/dsheirer/audio/squelch/SquelchStateEvent.java @@ -0,0 +1,72 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.audio.squelch; + +/** + * Squelch state change event + */ +public class SquelchStateEvent +{ + private SquelchState mSquelchState; + private int mTimeslot; + + public SquelchStateEvent(SquelchState squelchState, int timeslot) + { + mSquelchState = squelchState; + mTimeslot = timeslot; + } + + public SquelchState getSquelchState() + { + return mSquelchState; + } + + /** + * Timeslot associated with the squelch state + */ + public int getTimeslot() + { + return mTimeslot; + } + + /** + * Creates a squelch state event with a default timeslot of 0 + * @param squelchState for the event + * @return event + */ + public static SquelchStateEvent create(SquelchState squelchState) + { + return new SquelchStateEvent(squelchState, 0); + } + + /** + * Creates a squelch state event for the specified timeslot + * @param squelchState for the event + * @param timeslot that the event applies to + * @return event + */ + public static SquelchStateEvent create(SquelchState squelchState, int timeslot) + { + return new SquelchStateEvent(squelchState, timeslot); + } +} diff --git a/src/main/java/io/github/dsheirer/bits/BinaryMessage.java b/src/main/java/io/github/dsheirer/bits/BinaryMessage.java index 3a3e2cc6c..68667e7ad 100644 --- a/src/main/java/io/github/dsheirer/bits/BinaryMessage.java +++ b/src/main/java/io/github/dsheirer/bits/BinaryMessage.java @@ -1,20 +1,24 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014 Dennis Sheirer +/* * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - ******************************************************************************/ + */ package io.github.dsheirer.bits; import io.github.dsheirer.edac.CRC; @@ -285,19 +289,28 @@ public String toString() public String toHexString() { - int pointer = 0; - StringBuilder sb = new StringBuilder(); - while(pointer < size()) + for(int x = 0; x < size(); x += 4) { - sb.append(getHex(pointer, pointer + 3, 1)); - pointer += 4; + sb.append(getNibbleAsHex(x)); } return sb.toString(); } + /** + * Overrides the parent method which returns a BitSet so that we can return a BinaryMessage + * @param from + * @param to + * @return + */ + @Override + public BinaryMessage get(int from, int to) + { + return new BinaryMessage(super.get(from, to), (to - from)); + } + /** * Returns this bitset as an array of integer ones and zeros */ @@ -545,22 +558,23 @@ public byte getByte(int[] bits, int offset) } /** - * Returns the byte value contained between index and index + 7 bit positions + * Returns the byte value contained between index and index + 7 bit positions. If the length of this message is + * shorter than index + 7, then the least significant bits are set to zero in the returned value. * - * @param index specifying the start of the byte value + * @param startIndex specifying the start of the byte value * @return byte value contained at index <> index + 7 bit positions */ - public byte getByte(int index) + public byte getByte(int startIndex) { - Validate.isTrue((index + 7) <= size()); - int value = 0; for(int x = 0; x < 8; x++) { - value = value << 1; + value <<= 1; - if(get(index + x)) + int index = startIndex + x; + + if(index <= size() && get(index)) { value++; } @@ -569,6 +583,50 @@ public byte getByte(int index) return (byte)value; } + /** + * Converts the message to a byte array. + * + * Note: BitSet.toByteArray() outputs the bytes in big-endian (inverted) order. This method retains the correct + * endianness where bit 0 is the most significant bit of the first byte. + */ + public byte[] getBytes() + { + byte[] bytes = new byte[(int)Math.ceil((double)size() / 8.0)]; + + for(int x = 0; x < bytes.length; x++) + { + bytes[x] = getByte(x * 8); + } + + return bytes; + } + + /** + * Returns the 4-bit nibble value contained between index and index + 3 bit positions. If the length of this + * message is shorter than index + 3, then the least significant bits are set to zero in the returned value. + * + * @param startIndex specifying the start of the byte value + * @return nibble value contained at index <> index + 3 bit positions + */ + public int getNibble(int startIndex) + { + int value = 0; + + for(int x = 0; x < 4; x++) + { + value <<= 1; + + int index = startIndex + x; + + if(index <= size() && get(index)) + { + value++; + } + } + + return value; + } + /** * Sets the byte value at index position through index + 7 position. * @@ -627,6 +685,69 @@ public long getLong(int[] bits) return value; } + /** + * Returns the long value represented by the bit array + * + * @param bits - an array of bit positions that will be treated as if they + * were contiguous bits, with index 0 being the MSB and index + * length - 1 being the LSB + * @param offset to apply to each of the bits indices + * @return - integer value of the bit array + */ + public long getLong(int[] bits, int offset) + { + if(bits.length > 64) + { + throw new IllegalArgumentException("Overflow - must be 64 bits " + + "or less to fit into a primitive long value"); + } + + long value = 0; + + for(int index : bits) + { + value = Long.rotateLeft(value, 1); + + if(get(index + offset)) + { + value++; + } + } + + return value; + } + + /** + * Returns the bit values between start and end (inclusive) bit indices. If the overall length of the bit sequence + * is not a multiple of 8 bits, the value is zero padded with least significant bits to make it a multiple of 8. + * @param start index + * @param end index + * @return hexadecimal representation of the bit sequence + */ + public String getHex(int start, int end) + { + StringBuilder sb = new StringBuilder(); + + for(int x = start; x <= end; x += 4) + { + sb.append(getNibbleAsHex(x)); + } + + return sb.toString(); + } + + /** + * Format the byte value that starts at the specified index as hexadecimal. If the length of the message is less + * than the start index plus 7 bits, then the value represents those bits as high-order bits with zero padding in + * the least significant bits to make up the 8 bit value. + * @param startIndex of the byte. + * @return hexadecimal representation of the byte value + */ + public String getNibbleAsHex(int startIndex) + { + int value = getNibble(startIndex); + return Integer.toHexString(value).toUpperCase(); + } /** * Converts up to 63 bits from the bit array into an integer and then @@ -658,29 +779,6 @@ else if(bits.length <= 64) } } - public String getHex(int msb, int lsb, int digitDisplayCount) - { - int length = lsb - msb; - - if(length <= 32) - { - int value = getInt(msb, lsb); - - return String.format("%0" + digitDisplayCount + "X", value); - } - else if(length <= 64) - { - long value = getLong(msb, lsb); - - return String.format("%0" + digitDisplayCount + "X", value); - } - else - { - throw new IllegalArgumentException("BitSetBuffer.getHex() " - + "maximum array length is 64 bits"); - } - } - /** * Returns the int value represented by the bit range. This method will * parse the bits in big endian or little endian format. The start value @@ -877,6 +975,23 @@ public static int[] getFieldIndexes(int start, int length, boolean bigEndian) return checksumIndexes; } + /** + * Creates a binary message loaded with the byte array + * @param bytes to load + * @return loaded binary message + */ + public static BinaryMessage from(byte[] bytes) + { + BinaryMessage message = new BinaryMessage(bytes.length * 8); + + for(int x = 0; x < bytes.length; x++) + { + message.setByte(x * 8, bytes[x]); + } + + return message; + } + /** * Creates a bitsetbuffer loaded from a string of zeros and ones * @@ -998,4 +1113,20 @@ public void xor(int offset, int width, int value) this.xor(mask); } + + public static void main(String[] args) + { + BinaryMessage message = new BinaryMessage(10); + message.set(1); + message.set(4); + message.set(5); + message.set(8); + message.set(9); + + System.out.println("Hex: " + message.toHexString() + " Size:" + message.size()); + for(int x = 0; x < 10; x++) + { + System.out.println(x + ": " + message.getHex(x, x + 10)); + } + } } diff --git a/src/main/java/io/github/dsheirer/bits/CorrectedBinaryMessage.java b/src/main/java/io/github/dsheirer/bits/CorrectedBinaryMessage.java index a0465be1f..40dfa1603 100644 --- a/src/main/java/io/github/dsheirer/bits/CorrectedBinaryMessage.java +++ b/src/main/java/io/github/dsheirer/bits/CorrectedBinaryMessage.java @@ -1,21 +1,24 @@ -/******************************************************************************* - * sdrtrunk - * Copyright (C) 2014-2017 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.bits; import java.util.BitSet; @@ -48,6 +51,12 @@ public CorrectedBinaryMessage(byte[] data) super(data); } + public CorrectedBinaryMessage(BinaryMessage message) + { + this(message.size()); + this.xor(message); + } + @Override public int getCorrectedBitCount() { @@ -72,4 +81,16 @@ public void incrementCorrectedBitCount(int additionalCount) mCorrectedBitCount += additionalCount; } + /** + * Returns a new binary message containing the bits from (inclusive) to end (exclusive). + * + * @param start bit + * @param end bit + * @return message + */ + public CorrectedBinaryMessage getSubMessage(int start, int end) + { + BitSet subset = this.get(start, end); + return new CorrectedBinaryMessage(subset, end - start); + } } diff --git a/src/main/java/io/github/dsheirer/channel/IChannelDescriptor.java b/src/main/java/io/github/dsheirer/channel/IChannelDescriptor.java index 18a359639..05ccb6f5a 100644 --- a/src/main/java/io/github/dsheirer/channel/IChannelDescriptor.java +++ b/src/main/java/io/github/dsheirer/channel/IChannelDescriptor.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -19,7 +19,7 @@ */ package io.github.dsheirer.channel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; import io.github.dsheirer.protocol.Protocol; /** diff --git a/src/main/java/io/github/dsheirer/channel/metadata/ChannelMetadata.java b/src/main/java/io/github/dsheirer/channel/metadata/ChannelMetadata.java index fdd8ca4e5..5cb68e236 100644 --- a/src/main/java/io/github/dsheirer/channel/metadata/ChannelMetadata.java +++ b/src/main/java/io/github/dsheirer/channel/metadata/ChannelMetadata.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.channel.metadata; @@ -61,14 +63,31 @@ public class ChannelMetadata implements Listener, private List mFromIdentifierAliases; private Identifier mToIdentifier; private List mToIdentifierAliases; + private Integer mTimeslot; private IChannelMetadataUpdateListener mIChannelMetadataUpdateListener; private AliasModel mAliasModel; private AliasList mAliasList; - public ChannelMetadata(AliasModel aliasModel) + public ChannelMetadata(AliasModel aliasModel, Integer timeslot) { mAliasModel = aliasModel; + mTimeslot = timeslot; + } + + public ChannelMetadata(AliasModel aliasModel) + { + this(aliasModel, null); + } + + public Integer getTimeslot() + { + return mTimeslot; + } + + public boolean hasTimeslot() + { + return mTimeslot != null; } @Override @@ -242,6 +261,7 @@ private void broadcastUpdate(ChannelMetadataField field) @Override public void receive(IdentifierUpdateNotification update) { +// mLog.debug("Received update: " + update + " class:" + update.getIdentifier().getClass()); Identifier identifier = update.getIdentifier(); switch(identifier.getIdentifierClass()) diff --git a/src/main/java/io/github/dsheirer/channel/metadata/ChannelMetadataModel.java b/src/main/java/io/github/dsheirer/channel/metadata/ChannelMetadataModel.java index 33a19efdd..0b44878cd 100644 --- a/src/main/java/io/github/dsheirer/channel/metadata/ChannelMetadataModel.java +++ b/src/main/java/io/github/dsheirer/channel/metadata/ChannelMetadataModel.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.channel.metadata; @@ -24,6 +26,7 @@ import io.github.dsheirer.controller.channel.Channel; import io.github.dsheirer.eventbus.MyEventBus; import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.decoder.DecoderLogicalChannelNameIdentifier; import io.github.dsheirer.preference.PreferenceType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,6 +34,7 @@ import javax.swing.table.AbstractTableModel; import java.awt.EventQueue; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -77,7 +81,7 @@ public void preferenceUpdated(PreferenceType preferenceType) } - public void add(ChannelMetadata channelMetadata, Channel channel) + public void add(Collection channelMetadatas, Channel channel) { //Execute on the swing thread to avoid threading issues EventQueue.invokeLater(new Runnable() @@ -85,11 +89,14 @@ public void add(ChannelMetadata channelMetadata, Channel channel) @Override public void run() { - mChannelMetadata.add(channelMetadata); - mMetadataChannelMap.put(channelMetadata, channel); - int index = mChannelMetadata.indexOf(channelMetadata); - fireTableRowsInserted(index, index); - channelMetadata.setUpdateEventListener(ChannelMetadataModel.this); + for(ChannelMetadata channelMetadata: channelMetadatas) + { + mChannelMetadata.add(channelMetadata); + mMetadataChannelMap.put(channelMetadata, channel); + int index = mChannelMetadata.indexOf(channelMetadata); + fireTableRowsInserted(index, index); + channelMetadata.setUpdateEventListener(ChannelMetadataModel.this); + } } }); } @@ -161,6 +168,8 @@ public Class getColumnClass(int columnIndex) case COLUMN_USER_FROM_ALIAS: case COLUMN_USER_TO_ALIAS: return Alias.class; + case COLUMN_DECODER_LOGICAL_CHANNEL_NAME: + return String.class; default: return Identifier.class; } @@ -180,7 +189,30 @@ public Object getValueAt(int rowIndex, int columnIndex) case COLUMN_DECODER_TYPE: return channelMetadata.getDecoderTypeConfigurationIdentifier(); case COLUMN_DECODER_LOGICAL_CHANNEL_NAME: - return channelMetadata.getDecoderLogicalChannelNameIdentifier(); + DecoderLogicalChannelNameIdentifier id = channelMetadata.getDecoderLogicalChannelNameIdentifier(); + + if(channelMetadata.hasTimeslot()) + { + if(id == null) + { + return "TS:" + channelMetadata.getTimeslot(); + } + else + { + return id.getValue() + " TS:" + channelMetadata.getTimeslot(); + } + } + else + { + if(id == null) + { + return null; + } + else + { + return id.getValue(); + } + } case COLUMN_CONFIGURATION_FREQUENCY: return channelMetadata.getFrequencyConfigurationIdentifier(); case COLUMN_CONFIGURATION_CHANNEL: diff --git a/src/main/java/io/github/dsheirer/channel/metadata/ChannelMetadataPanel.java b/src/main/java/io/github/dsheirer/channel/metadata/ChannelMetadataPanel.java index 30da50703..13fc3f129 100644 --- a/src/main/java/io/github/dsheirer/channel/metadata/ChannelMetadataPanel.java +++ b/src/main/java/io/github/dsheirer/channel/metadata/ChannelMetadataPanel.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.channel.metadata; @@ -128,7 +130,7 @@ private void init() private void setColors() { mBackgroundColors.put(State.ACTIVE, Color.CYAN); - mForegroundColors.put(State.ACTIVE, Color.YELLOW); + mForegroundColors.put(State.ACTIVE, Color.BLUE); mBackgroundColors.put(State.CALL, Color.BLUE); mForegroundColors.put(State.CALL, Color.YELLOW); mBackgroundColors.put(State.CONTROL, Color.ORANGE); diff --git a/src/main/java/io/github/dsheirer/channel/state/AbstractChannelState.java b/src/main/java/io/github/dsheirer/channel/state/AbstractChannelState.java new file mode 100644 index 000000000..2c93486c9 --- /dev/null +++ b/src/main/java/io/github/dsheirer/channel/state/AbstractChannelState.java @@ -0,0 +1,187 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.channel.state; + +import io.github.dsheirer.audio.squelch.ISquelchStateProvider; +import io.github.dsheirer.channel.metadata.ChannelMetadata; +import io.github.dsheirer.controller.channel.Channel; +import io.github.dsheirer.controller.channel.ChannelEvent; +import io.github.dsheirer.controller.channel.IChannelEventProvider; +import io.github.dsheirer.identifier.IdentifierUpdateNotification; +import io.github.dsheirer.identifier.IdentifierUpdateProvider; +import io.github.dsheirer.module.Module; +import io.github.dsheirer.module.decode.event.IDecodeEvent; +import io.github.dsheirer.module.decode.event.IDecodeEventProvider; +import io.github.dsheirer.sample.IOverflowListener; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.source.ISourceEventProvider; +import io.github.dsheirer.source.SourceEvent; +import io.github.dsheirer.source.heartbeat.Heartbeat; +import io.github.dsheirer.source.heartbeat.IHeartbeatListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; + +public abstract class AbstractChannelState extends Module implements IChannelEventProvider, IDecodeEventProvider, + IDecoderStateEventProvider, ISourceEventProvider, IHeartbeatListener, ISquelchStateProvider, + IdentifierUpdateProvider, IOverflowListener +{ + private final static Logger mLog = LoggerFactory.getLogger(AbstractChannelState.class); + + protected Listener mChannelEventListener; + protected Listener mDecodeEventListener; + protected Listener mDecoderStateListener; + protected Listener mExternalSourceEventListener; + protected Channel mChannel; + protected boolean mSourceOverflow = false; + private HeartbeatReceiver mHeartbeatReceiver = new HeartbeatReceiver(); + + public AbstractChannelState(Channel channel) + { + mChannel = channel; + } + + /** + * Invoked each time that a heartbeat is received so that sub-class implementations can check current timers and + * adjust channel state as necessary. The heartbeat arrives on a periodic basis independent of any decoded + * messages so that channel state is not entirely dependent on a continuous decoded message stream. + */ + protected abstract void checkState(); + + public abstract Collection getChannelMetadata(); + + public abstract void updateChannelStateIdentifiers(IdentifierUpdateNotification notification); + + /** + * Receiver inner class that implements the IHeartbeatListener interface to receive heartbeat messages. + */ + @Override + public Listener getHeartbeatListener() + { + return mHeartbeatReceiver; + } + + /** + * This method is invoked if the source buffer provider goes into overflow state. Since this is an external state, + * we use the mSourceOverflow variable to override the internal state reported to external listeners. + * + * @param overflow true to indicate an overflow state + */ + @Override + public void sourceOverflow(boolean overflow) + { + mSourceOverflow = overflow; + } + + /** + * Indicates if this channel's sample buffer is in overflow state, meaning that the inbound sample + * stream is not being processed fast enough and samples are being thrown away until the processing can + * catch up. + * + * @return true if the channel is in overflow state. + */ + public boolean isOverflow() + { + return mSourceOverflow; + } + + @Override + public void setChannelEventListener(Listener listener) + { + mChannelEventListener = listener; + } + + @Override + public void removeChannelEventListener() + { + mChannelEventListener = null; + } + + @Override + public void addDecodeEventListener(Listener listener) + { + mDecodeEventListener = listener; + } + + @Override + public void removeDecodeEventListener(Listener listener) + { + mDecodeEventListener = null; + } + + /** + * Adds a decoder state event listener + */ + @Override + public void setDecoderStateListener(Listener listener) + { + mDecoderStateListener = listener; + } + + /** + * Removes the decoder state event listener + */ + @Override + public void removeDecoderStateListener() + { + mDecoderStateListener = null; + } + + /** + * Registers the listener to receive source events from the channel state + */ + @Override + public void setSourceEventListener(Listener listener) + { + mExternalSourceEventListener = listener; + } + + /** + * De-Registers a listener from receiving source events from the channel state + */ + @Override + public void removeSourceEventListener() + { + mExternalSourceEventListener = null; + } + + /** + * Processes periodic heartbeats received from the processing chain to perform state monitoring and cleanup + * functions. + * + * Monitors decoder state events to automatically transition the channel state to IDLE (standard channel) or to + * TEARDOWN (traffic channel) when decoding stops or the monitored channel returns to a no signal state. + * + * Provides a FADE transition state to allow for momentary decoding dropouts and to allow the user access to call + * details for a fade period upon call end. + */ + public class HeartbeatReceiver implements Listener + { + @Override + public void receive(Heartbeat heartbeat) + { + checkState(); + } + } +} diff --git a/src/main/java/io/github/dsheirer/channel/state/AbstractDecoderState.java b/src/main/java/io/github/dsheirer/channel/state/AbstractDecoderState.java new file mode 100644 index 000000000..2ec19bedd --- /dev/null +++ b/src/main/java/io/github/dsheirer/channel/state/AbstractDecoderState.java @@ -0,0 +1,148 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.channel.state; + +import io.github.dsheirer.identifier.IdentifierUpdateListener; +import io.github.dsheirer.identifier.IdentifierUpdateProvider; +import io.github.dsheirer.message.IMessage; +import io.github.dsheirer.message.IMessageListener; +import io.github.dsheirer.module.Module; +import io.github.dsheirer.module.decode.DecoderType; +import io.github.dsheirer.module.decode.event.ActivitySummaryProvider; +import io.github.dsheirer.module.decode.event.IDecodeEvent; +import io.github.dsheirer.module.decode.event.IDecodeEventProvider; +import io.github.dsheirer.sample.Broadcaster; +import io.github.dsheirer.sample.Listener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractDecoderState extends Module implements ActivitySummaryProvider, Listener, + IDecodeEventProvider, IDecoderStateEventListener, IDecoderStateEventProvider, IMessageListener, + IdentifierUpdateProvider, IdentifierUpdateListener +{ + private final static Logger mLog = LoggerFactory.getLogger(AbstractDecoderState.class); + protected String DIVIDER1 = "======================================================\n"; + protected String DIVIDER2 = "------------------------------------------------------\n"; + /* This has to be a broadcaster in order for references to persist */ + protected Broadcaster mDecodeEventBroadcaster = new Broadcaster<>(); + protected Listener mDecoderStateListener; + private DecoderStateEventListener mDecoderStateEventListener = new DecoderStateEventListener(); + + public abstract DecoderType getDecoderType(); + + /** + * Provides subclass reference to the decode event broadcaster + */ + protected Broadcaster getDecodeEventBroadcaster() + { + return mDecodeEventBroadcaster; + } + + @Override + public Listener getMessageListener() + { + return this; + } + + /** + * Implements the IDecoderStateEventListener interface to receive state + * reset events. + */ + public abstract void receiveDecoderStateEvent(DecoderStateEvent event); + + /** + * Activity Summary - textual summary of activity observed by the channel state. + */ + public abstract String getActivitySummary(); + + /** + * Broadcasts a decode event to any registered listeners + */ + protected void broadcast(IDecodeEvent event) + { + mDecodeEventBroadcaster.broadcast(event); + } + + /** + * Adds a call event listener + */ + @Override + public void addDecodeEventListener(Listener listener) + { + mDecodeEventBroadcaster.addListener(listener); + } + + /** + * Removes the call event listener + */ + @Override + public void removeDecodeEventListener(Listener listener) + { + mDecodeEventBroadcaster.removeListener(listener); + } + + @Override + public Listener getDecoderStateListener() + { + return mDecoderStateEventListener; + } + + /** + * Broadcasts a channel state event to any registered listeners + */ + protected void broadcast(DecoderStateEvent event) + { + if(mDecoderStateListener != null) + { + mDecoderStateListener.receive(event); + } + } + + /** + * Adds a decoder state event listener + */ + @Override + public void setDecoderStateListener(Listener listener) + { + mDecoderStateListener = listener; + } + + /** + * Removes the decoder state event listener + */ + @Override + public void removeDecoderStateListener() + { + mDecoderStateListener = null; + } + + private class DecoderStateEventListener implements Listener + { + @Override + public void receive(DecoderStateEvent event) + { + receiveDecoderStateEvent(event); + } + } + +} diff --git a/src/main/java/io/github/dsheirer/channel/state/AlwaysUnsquelchedDecoderState.java b/src/main/java/io/github/dsheirer/channel/state/AlwaysUnsquelchedDecoderState.java index 4d145b907..310046b81 100644 --- a/src/main/java/io/github/dsheirer/channel/state/AlwaysUnsquelchedDecoderState.java +++ b/src/main/java/io/github/dsheirer/channel/state/AlwaysUnsquelchedDecoderState.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.channel.state; @@ -48,11 +50,6 @@ public void init() { } - @Override - public void reset() - { - } - @Override public String getActivitySummary() { diff --git a/src/main/java/io/github/dsheirer/channel/state/ChangeChannelTimeoutEvent.java b/src/main/java/io/github/dsheirer/channel/state/ChangeChannelTimeoutEvent.java index df7679a40..6e5bb3081 100644 --- a/src/main/java/io/github/dsheirer/channel/state/ChangeChannelTimeoutEvent.java +++ b/src/main/java/io/github/dsheirer/channel/state/ChangeChannelTimeoutEvent.java @@ -1,3 +1,25 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + package io.github.dsheirer.channel.state; import io.github.dsheirer.controller.channel.Channel.ChannelType; @@ -7,23 +29,28 @@ */ public class ChangeChannelTimeoutEvent extends DecoderStateEvent { - private ChannelType mChannelType; - private long mCallTimeout; - - public ChangeChannelTimeoutEvent( Object source, ChannelType channelType, long timeout ) - { - super( source, Event.CHANGE_CALL_TIMEOUT, State.IDLE ); - mChannelType = channelType; - mCallTimeout = timeout; - } - - public ChannelType getChannelType() - { - return mChannelType; - } - - public long getCallTimeout() - { - return mCallTimeout; - } + private ChannelType mChannelType; + private long mCallTimeout; + + public ChangeChannelTimeoutEvent(Object source, ChannelType channelType, long timeout, int timeslot) + { + super(source, Event.CHANGE_CALL_TIMEOUT, State.IDLE, timeslot); + mChannelType = channelType; + mCallTimeout = timeout; + } + + public ChangeChannelTimeoutEvent(Object source, ChannelType channelType, long timeout) + { + this(source, channelType, timeout, 0); + } + + public ChannelType getChannelType() + { + return mChannelType; + } + + public long getCallTimeout() + { + return mCallTimeout; + } } \ No newline at end of file diff --git a/src/main/java/io/github/dsheirer/channel/state/ChannelState.java b/src/main/java/io/github/dsheirer/channel/state/ChannelState.java deleted file mode 100644 index bc4097f1f..000000000 --- a/src/main/java/io/github/dsheirer/channel/state/ChannelState.java +++ /dev/null @@ -1,762 +0,0 @@ -/* - * ****************************************************************************** - * sdrtrunk - * 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 - * ***************************************************************************** - */ -package io.github.dsheirer.channel.state; - -import io.github.dsheirer.alias.AliasModel; -import io.github.dsheirer.audio.squelch.ISquelchStateProvider; -import io.github.dsheirer.audio.squelch.SquelchState; -import io.github.dsheirer.channel.metadata.ChannelMetadata; -import io.github.dsheirer.channel.state.DecoderStateEvent.Event; -import io.github.dsheirer.controller.channel.Channel; -import io.github.dsheirer.controller.channel.Channel.ChannelType; -import io.github.dsheirer.controller.channel.ChannelEvent; -import io.github.dsheirer.controller.channel.IChannelEventProvider; -import io.github.dsheirer.identifier.IdentifierClass; -import io.github.dsheirer.identifier.IdentifierUpdateListener; -import io.github.dsheirer.identifier.IdentifierUpdateNotification; -import io.github.dsheirer.identifier.IdentifierUpdateProvider; -import io.github.dsheirer.identifier.MutableIdentifierCollection; -import io.github.dsheirer.identifier.configuration.AliasListConfigurationIdentifier; -import io.github.dsheirer.identifier.configuration.ChannelNameConfigurationIdentifier; -import io.github.dsheirer.identifier.configuration.DecoderTypeConfigurationIdentifier; -import io.github.dsheirer.identifier.configuration.FrequencyConfigurationIdentifier; -import io.github.dsheirer.identifier.configuration.SiteConfigurationIdentifier; -import io.github.dsheirer.identifier.configuration.SystemConfigurationIdentifier; -import io.github.dsheirer.identifier.decoder.ChannelStateIdentifier; -import io.github.dsheirer.module.Module; -import io.github.dsheirer.module.decode.config.DecodeConfiguration; -import io.github.dsheirer.module.decode.event.IDecodeEvent; -import io.github.dsheirer.module.decode.event.IDecodeEventProvider; -import io.github.dsheirer.sample.IOverflowListener; -import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.source.ISourceEventListener; -import io.github.dsheirer.source.ISourceEventProvider; -import io.github.dsheirer.source.SourceEvent; -import io.github.dsheirer.source.SourceType; -import io.github.dsheirer.source.config.SourceConfigTuner; -import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency; -import io.github.dsheirer.source.heartbeat.Heartbeat; -import io.github.dsheirer.source.heartbeat.IHeartbeatListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; - -public class ChannelState extends Module implements IChannelEventProvider, IDecodeEventProvider, - IDecoderStateEventListener, IDecoderStateEventProvider, ISourceEventListener, ISourceEventProvider, - IHeartbeatListener, ISquelchStateProvider, IOverflowListener, IdentifierUpdateListener, IdentifierUpdateProvider -{ - private final static Logger mLog = LoggerFactory.getLogger(ChannelState.class); - - public static final long FADE_TIMEOUT_DELAY = 1200; - public static final long RESET_TIMEOUT_DELAY = 2000; - - private State mState = State.IDLE; - private MutableIdentifierCollection mIdentifierCollection = new MutableIdentifierCollection(); - private Listener mChannelEventListener; - private Listener mDecodeEventListener; - private Listener mDecoderStateListener; - private Listener mSquelchStateListener; - private Listener mExternalSourceEventListener; - private DecoderStateEventReceiver mDecoderStateEventReceiver = new DecoderStateEventReceiver(); - private HeartbeatReceiver mHeartbeatReceiver = new HeartbeatReceiver(); - private Channel mChannel; - private SourceEventListener mInternalSourceEventListener; - private ChannelMetadata mChannelMetadata; - private IdentifierUpdateNotificationProxy mIdentifierUpdateNotificationProxy = new IdentifierUpdateNotificationProxy(); - - private boolean mSquelchLocked = false; - private boolean mSelected = false; - private boolean mSourceOverflow = false; - - private long mStandardChannelFadeTimeout = FADE_TIMEOUT_DELAY; - private long mTrafficChannelFadeTimeout = DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS * 1000; - private long mFadeTimeout; - private long mEndTimeout; - - - /** - * Channel state tracks the overall state of all processing modules and decoders configured for the channel and - * provides squelch control and decoder state reset events. - * - * Uses a state enumeration that defines allowable channel state transitions in order to track a call or data decode - * event from start to finish. Uses a timer to monitor for inactivity and to provide a FADE period that indicates - * to the user that the activity has stopped while continuing to provide details about the call, before the state is - * reset to IDLE. - * - * State Descriptions: - * IDLE: Normal state. No voice or data call activity - * CALL/DATA/ENCRYPTED/CONTROL: Decoding states. - * FADE: The phase after a voice or data call when either an explicit call end has been received, or when no new - * signalling updates have been received, and the fade timer has expired. This phase allows for gui updates to - * signal to the user that the call is ended, while continuing to display the call details for the user - * TEARDOWN: Indicates a traffic channel that will be torn down for reuse. - */ - public ChannelState(Channel channel, AliasModel aliasModel) - { - mChannel = channel; - mChannelMetadata = new ChannelMetadata(aliasModel); - mIdentifierCollection.setIdentifierUpdateListener(mIdentifierUpdateNotificationProxy); - createConfigurationIdentifiers(channel); - } - - /** - * Creates configuration identifiers for the channel name, system, site and alias list name. - */ - private void createConfigurationIdentifiers(Channel channel) - { - mIdentifierCollection.update(DecoderTypeConfigurationIdentifier.create(channel.getDecodeConfiguration().getDecoderType())); - - if(channel.hasSystem()) - { - mIdentifierCollection.update(SystemConfigurationIdentifier.create(channel.getSystem())); - } - if(channel.hasSite()) - { - mIdentifierCollection.update(SiteConfigurationIdentifier.create(channel.getSite())); - } - if(channel.getName() != null && !channel.getName().isEmpty()) - { - mIdentifierCollection.update(ChannelNameConfigurationIdentifier.create(channel.getName())); - } - if(channel.getAliasListName() != null && !channel.getAliasListName().isEmpty()) - { - mIdentifierCollection.update(AliasListConfigurationIdentifier.create(channel.getAliasListName())); - } - if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER) - { - long frequency = ((SourceConfigTuner)channel.getSourceConfiguration()).getFrequency(); - mIdentifierCollection.update(FrequencyConfigurationIdentifier.create(frequency)); - } - else if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER_MULTIPLE_FREQUENCIES) - { - List frequencies = ((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).getFrequencies(); - - if(frequencies.size() > 0) - { - mIdentifierCollection.update(FrequencyConfigurationIdentifier.create(frequencies.get(0))); - } - } - } - - /** - * Interface to receive channel identifier updates from this channel state and from any - * decoder states. - */ - @Override - public Listener getIdentifierUpdateListener() - { - return mChannelMetadata; - } - - /** - * Updates the channel state identifier collection using the update notification. This update will be reflected - * in the internal channel state and will also be broadcast to any listeners, including the channel metadata for - * this channel state. - */ - public void updateChannelStateIdentifiers(IdentifierUpdateNotification notification) - { - mIdentifierCollection.receive(notification); - } - - @Override - public void setIdentifierUpdateListener(Listener listener) - { - mIdentifierUpdateNotificationProxy.setListener(listener); - } - - @Override - public void removeIdentifierUpdateListener() - { - mIdentifierUpdateNotificationProxy.removeListener(); - } - - /** - * Channel metadata for this channel. - */ - public ChannelMetadata getChannelMetadata() - { - return mChannelMetadata; - } - - /** - * Resets this channel state and prepares it for reuse. - */ - @Override - public void reset() - { - mState = State.IDLE; - broadcast(new DecoderStateEvent(this, Event.RESET, State.IDLE)); - mIdentifierCollection.remove(IdentifierClass.USER); - mIdentifierCollection.update(ChannelStateIdentifier.IDLE); - mSourceOverflow = false; - } - - @Override - public void start() - { - mIdentifierCollection.broadcastIdentifiers(); - - if(mChannel.getChannelType() == ChannelType.TRAFFIC) - { - setState(State.CALL); - } - } - - @Override - public void stop() - { - processTeardownState(); - mSquelchLocked = false; - } - - public void dispose() - { - mDecodeEventListener = null; - mDecoderStateListener = null; - mSquelchStateListener = null; - } - - @Override - public Listener getSourceEventListener() - { - if(mInternalSourceEventListener == null) - { - mInternalSourceEventListener = new SourceEventListener(); - } - - return mInternalSourceEventListener; - } - - public void setStandardChannelTimeout(long milliseconds) - { - mStandardChannelFadeTimeout = milliseconds; - - if(mChannel.isStandardChannel()) - { - mFadeTimeout = mStandardChannelFadeTimeout; - } - } - - public void setTrafficChannelTimeout(long milliseconds) - { - mTrafficChannelFadeTimeout = milliseconds; - - if(mChannel.isTrafficChannel()) - { - mFadeTimeout = System.currentTimeMillis() + mTrafficChannelFadeTimeout; - } - } - - public void setSelected(boolean selected) - { - mSelected = selected; - } - - public boolean isSelected() - { - return mSelected; - } - - public State getState() - { - return mState; - } - - /** - * Updates the fade timeout threshold to the current time plus delay - */ - private void updateFadeTimeout() - { - if(mChannel.isTrafficChannel()) - { - mFadeTimeout = System.currentTimeMillis() + mTrafficChannelFadeTimeout; - } - else - { - mFadeTimeout = System.currentTimeMillis() + mStandardChannelFadeTimeout; - } - - } - - /** - * Updates the reset timeout threshold to the current time plus delay - */ - private void updateResetTimeout() - { - if(mChannel.isTrafficChannel()) - { - mEndTimeout = System.currentTimeMillis(); - } - else - { - mEndTimeout = System.currentTimeMillis() + RESET_TIMEOUT_DELAY; - } - } - - /** - * Broadcasts the squelch state to the registered listener - */ - protected void broadcast(SquelchState state) - { - if(mSquelchStateListener != null && !mSquelchLocked) - { - mSquelchStateListener.receive(state); - } - } - - /** - * Broadcasts the source event to a registered external source event listener - */ - protected void broadcast(SourceEvent sourceEvent) - { - if(mExternalSourceEventListener != null) - { - mExternalSourceEventListener.receive(sourceEvent); - } - } - - /** - * Sets the squelch state listener - */ - @Override - public void setSquelchStateListener(Listener listener) - { - mSquelchStateListener = listener; - } - - /** - * Removes the squelch state listener - */ - @Override - public void removeSquelchStateListener() - { - mSquelchStateListener = null; - } - - /** - * Sets the channel state to the specified state, or updates the timeout values so that the state monitor will not - * change state. Broadcasts a squelch event when the state changes and the audio squelch state should change. Also - * broadcasts changed attribute and decoder state events so that external processes can maintain sync with this - * channel state. - */ - protected void setState(State state) - { - if(state == mState) - { - if(State.CALL_STATES.contains(state)) - { - updateFadeTimeout(); - } - } - else if(mState.canChangeTo(state)) - { - switch(state) - { - case ACTIVE: - broadcast(SquelchState.SQUELCH); - updateFadeTimeout(); - mState = state; - mIdentifierCollection.update(ChannelStateIdentifier.ACTIVE); - break; - case CONTROL: - //Don't allow traffic channels to be control channels, otherwise they can't transition to teardown - if(mChannel.isStandardChannel()) - { - broadcast(SquelchState.SQUELCH); - updateFadeTimeout(); - mState = state; - mIdentifierCollection.update(ChannelStateIdentifier.CONTROL); - } - break; - case DATA: - broadcast(SquelchState.SQUELCH); - updateFadeTimeout(); - mState = state; - mIdentifierCollection.update(ChannelStateIdentifier.DATA); - break; - case ENCRYPTED: - broadcast(SquelchState.SQUELCH); - updateFadeTimeout(); - mState = state; - mIdentifierCollection.update(ChannelStateIdentifier.ENCRYPTED); - break; - case CALL: - broadcast(SquelchState.UNSQUELCH); - updateFadeTimeout(); - mState = state; - mIdentifierCollection.update(ChannelStateIdentifier.CALL); - break; - case FADE: - processFadeState(); - mIdentifierCollection.update(ChannelStateIdentifier.FADE); - break; - case IDLE: - processIdleState(); - mIdentifierCollection.update(ChannelStateIdentifier.IDLE); - break; - case TEARDOWN: - processTeardownState(); - break; - case RESET: - mState = State.IDLE; - mIdentifierCollection.update(ChannelStateIdentifier.IDLE); - break; - default: - break; - } - } - } - - /** - * Receiver inner class that implements the IHeartbeatListener interface to receive heartbeat messages. - */ - @Override - public Listener getHeartbeatListener() - { - return mHeartbeatReceiver; - } - - /** - * This method is invoked if the source buffer provider goes into overflow state. Since this is an external state, - * we use the mSourceOverflow variable to override the internal state reported to external listeners. - * - * @param overflow true to indicate an overflow state - */ - @Override - public void sourceOverflow(boolean overflow) - { - mSourceOverflow = overflow; - } - - /** - * Indicates if this channel's sample buffer is in overflow state, meaning that the inbound sample - * stream is not being processed fast enough and samples are being thrown away until the processing can - * catch up. - * - * @return true if the channel is in overflow state. - */ - public boolean isOverflow() - { - return mSourceOverflow; - } - - /** - * Sets the state and processes related actions - */ - private void processFadeState() - { - updateResetTimeout(); - mState = State.FADE; - mIdentifierCollection.update(ChannelStateIdentifier.FADE); - - broadcast(SquelchState.SQUELCH); - } - - private void processIdleState() - { - broadcast(SquelchState.SQUELCH); - - if(mState == State.FADE) - { - broadcast(new DecoderStateEvent(this, Event.RESET, State.IDLE)); - } - - mState = State.IDLE; - mIdentifierCollection.update(ChannelStateIdentifier.IDLE); - } - - private void processTeardownState() - { - broadcast(SquelchState.SQUELCH); - - mState = State.TEARDOWN; - mIdentifierCollection.update(ChannelStateIdentifier.TEARDOWN); - - if(mChannel.isTrafficChannel()) - { - broadcast(new ChannelEvent(mChannel, ChannelEvent.Event.REQUEST_DISABLE)); - } - } - - /** - * Broadcasts the call event to the registered listener - */ - protected void broadcast(IDecodeEvent event) - { - if(mDecodeEventListener != null) - { - mDecodeEventListener.receive(event); - } - } - - /** - * Broadcasts the channel event to a registered listener - */ - private void broadcast(ChannelEvent channelEvent) - { - if(mChannelEventListener != null) - { - mChannelEventListener.receive(channelEvent); - } - } - - @Override - public void setChannelEventListener(Listener listener) - { - mChannelEventListener = listener; - } - - @Override - public void removeChannelEventListener() - { - mChannelEventListener = null; - } - - @Override - public void addDecodeEventListener(Listener listener) - { - mDecodeEventListener = listener; - } - - @Override - public void removeDecodeEventListener(Listener listener) - { - mDecodeEventListener = null; - } - - /** - * Broadcasts a channel state event to any registered listeners - */ - protected void broadcast(DecoderStateEvent event) - { - if(mDecoderStateListener != null) - { - mDecoderStateListener.receive(event); - } - } - - /** - * Adds a decoder state event listener - */ - @Override - public void setDecoderStateListener(Listener listener) - { - mDecoderStateListener = listener; - } - - /** - * Removes the decoder state event listener - */ - @Override - public void removeDecoderStateListener() - { - mDecoderStateListener = null; - } - - @Override - public Listener getDecoderStateListener() - { - return mDecoderStateEventReceiver; - } - - /** - * Registers the listener to receive source events from the channel state - */ - @Override - public void setSourceEventListener(Listener listener) - { - mExternalSourceEventListener = listener; - } - - /** - * De-Registers a listener from receiving source events from the channel state - */ - @Override - public void removeSourceEventListener() - { - mExternalSourceEventListener = null; - } - - /** - * Listener to receive source events. - */ - public class SourceEventListener implements Listener - { - @Override - public void receive(SourceEvent sourceEvent) - { - switch(sourceEvent.getEvent()) - { - case NOTIFICATION_FREQUENCY_CHANGE: - //Rebroadcast source frequency change events for the decoder(s) to process - long frequency = sourceEvent.getValue().longValue(); - broadcast(new DecoderStateEvent(this, Event.SOURCE_FREQUENCY, getState(), frequency)); - - //Create a new frequency configuration identifier so that downstream consumers receive the change - //via channel metadata and audio packet updates - this is a silent add that is sent as a notification - //to all identifier collections so that they don't rebroadcast the change and cause a feedback loop - mIdentifierUpdateNotificationProxy.receive(new IdentifierUpdateNotification( - FrequencyConfigurationIdentifier.create(frequency), IdentifierUpdateNotification.Operation.SILENT_ADD)); - break; - case NOTIFICATION_MEASURED_FREQUENCY_ERROR: - //Rebroadcast frequency error measurements to external listener if we're currently - //in an active (ie sync locked) state. - if(getState().isActiveState()) - { - broadcast(SourceEvent.frequencyErrorMeasurementSyncLocked(sourceEvent.getValue().longValue(), - mChannel.getChannelType().name())); - } - break; - } - } - } - - /** - * DecoderStateEvent receiver wrapper - */ - public class DecoderStateEventReceiver implements Listener - { - @Override - public void receive(DecoderStateEvent event) - { - if(event.getSource() != this) - { - switch(event.getEvent()) - { - case ALWAYS_UNSQUELCH: - broadcast(SquelchState.UNSQUELCH); - mSquelchLocked = true; - break; - case CHANGE_CALL_TIMEOUT: - if(event instanceof ChangeChannelTimeoutEvent) - { - ChangeChannelTimeoutEvent timeout = (ChangeChannelTimeoutEvent)event; - - if(timeout.getChannelType() == ChannelType.STANDARD) - { - setStandardChannelTimeout(timeout.getCallTimeout()); - } - else - { - setTrafficChannelTimeout(timeout.getCallTimeout()); - } - } - case CONTINUATION: - case DECODE: - case START: - if(State.CALL_STATES.contains(event.getState())) - { - setState(event.getState()); - } - break; - case END: - if(mChannel.isTrafficChannel()) - { - setState(State.TEARDOWN); - } - else - { - setState(State.FADE); - } - break; - case RESET: - /* Channel State does not respond to reset events */ - break; - default: - break; - } - } - } - } - - /** - * Processes periodic heartbeats received from the processing chain to perform state monitoring and cleanup - * functions. - * - * Monitors decoder state events to automatically transition the channel state to IDLE (standard channel) or to - * TEARDOWN (traffic channel) when decoding stops or the monitored channel returns to a no signal state. - * - * Provides a FADE transition state to allow for momentary decoding dropouts and to allow the user access to call - * details for a fade period upon call end. - */ - public class HeartbeatReceiver implements Listener - { - @Override - public void receive(Heartbeat heartbeat) - { - try - { - if(State.CALL_STATES.contains(mState) && mFadeTimeout <= System.currentTimeMillis()) - { - processFadeState(); - } - else if(mState == State.FADE && mEndTimeout <= System.currentTimeMillis()) - { - if(mChannel.isTrafficChannel()) - { - processTeardownState(); - } - else - { - processIdleState(); - } - } - } - catch(Throwable e) - { - mLog.error("An error occurred while state monitor was running " + - "- state [" + getState() + - "] current [" + System.currentTimeMillis() + - "] mResetTimeout [" + mEndTimeout + - "] mFadeTimeout [" + mFadeTimeout + - "]", e); - } - } - } - - /** - * Proxy between the identifier collection and the external update notification listener. This proxy enables - * access to internal components to broadcast silent identifier update notifications externally. - */ - public class IdentifierUpdateNotificationProxy implements Listener - { - private Listener mIdentifierUpdateNotificationListener; - - @Override - public void receive(IdentifierUpdateNotification identifierUpdateNotification) - { - if(mIdentifierUpdateNotificationListener != null) - { - mIdentifierUpdateNotificationListener.receive(identifierUpdateNotification); - } - } - - public void setListener(Listener listener) - { - mIdentifierUpdateNotificationListener = listener; - } - - public void removeListener() - { - mIdentifierUpdateNotificationListener = null; - } - } -} diff --git a/src/main/java/io/github/dsheirer/channel/state/ChannelStateSelectionListener.java b/src/main/java/io/github/dsheirer/channel/state/ChannelStateSelectionListener.java deleted file mode 100644 index cbdbcf93a..000000000 --- a/src/main/java/io/github/dsheirer/channel/state/ChannelStateSelectionListener.java +++ /dev/null @@ -1,24 +0,0 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014 Dennis Sheirer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - ******************************************************************************/ -package io.github.dsheirer.channel.state; - - -public interface ChannelStateSelectionListener -{ - public void selected( ChannelState channelState ); -} diff --git a/src/main/java/io/github/dsheirer/channel/state/DecoderState.java b/src/main/java/io/github/dsheirer/channel/state/DecoderState.java index 68267a96b..fbb24a8bc 100644 --- a/src/main/java/io/github/dsheirer/channel/state/DecoderState.java +++ b/src/main/java/io/github/dsheirer/channel/state/DecoderState.java @@ -1,43 +1,33 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.channel.state; import io.github.dsheirer.channel.IChannelDescriptor; -import io.github.dsheirer.identifier.Form; -import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.identifier.IdentifierClass; -import io.github.dsheirer.identifier.IdentifierUpdateListener; import io.github.dsheirer.identifier.IdentifierUpdateNotification; -import io.github.dsheirer.identifier.IdentifierUpdateProvider; import io.github.dsheirer.identifier.MutableIdentifierCollection; import io.github.dsheirer.identifier.configuration.ChannelDescriptorConfigurationIdentifier; import io.github.dsheirer.identifier.configuration.DecoderTypeConfigurationIdentifier; -import io.github.dsheirer.message.IMessage; -import io.github.dsheirer.message.IMessageListener; -import io.github.dsheirer.module.Module; -import io.github.dsheirer.module.decode.DecoderType; -import io.github.dsheirer.module.decode.event.ActivitySummaryProvider; -import io.github.dsheirer.module.decode.event.IDecodeEvent; -import io.github.dsheirer.module.decode.event.IDecodeEventProvider; -import io.github.dsheirer.sample.Broadcaster; import io.github.dsheirer.sample.Listener; /** @@ -46,27 +36,22 @@ * * Provides access to a textual activity summary of events observed. */ -public abstract class DecoderState extends Module implements ActivitySummaryProvider, Listener, - IDecodeEventProvider, IDecoderStateEventListener, IDecoderStateEventProvider, IMessageListener, - IdentifierUpdateProvider, IdentifierUpdateListener +public abstract class DecoderState extends AbstractDecoderState { -// private final static Logger mLog = LoggerFactory.getLogger(DecoderState.class); + private MutableIdentifierCollection mIdentifierCollection; + protected Listener mConfigurationIdentifierListener; + protected IChannelDescriptor mCurrentChannel; - protected String DIVIDER1 = "======================================================\n"; - protected String DIVIDER2 = "------------------------------------------------------\n"; - - /* This has to be a broadcaster in order for references to persist */ - private Broadcaster mDecodeEventBroadcaster = new Broadcaster<>(); - private Listener mDecoderStateListener; - private DecoderStateEventListener mDecoderStateEventListener = new DecoderStateEventListener(); - private MutableIdentifierCollection mIdentifierCollection = new MutableIdentifierCollection(); - private ConfigurationIdentifierListener mConfigurationIdentifierListener = new ConfigurationIdentifierListener(); - - private IChannelDescriptor mCurrentChannel; + public DecoderState(MutableIdentifierCollection mutableIdentifierCollection) + { + mIdentifierCollection = mutableIdentifierCollection; + mIdentifierCollection.update(new DecoderTypeConfigurationIdentifier(getDecoderType())); + } public DecoderState() { - mIdentifierCollection.update(new DecoderTypeConfigurationIdentifier(getDecoderType())); + this(new MutableIdentifierCollection()); + mConfigurationIdentifierListener = new ConfigurationIdentifierListener(); } @Override @@ -76,16 +61,6 @@ public void start() mIdentifierCollection.broadcastIdentifiers(); } - public abstract DecoderType getDecoderType(); - - /** - * Current collection of identifiers managed by the decoder state. - */ - public MutableIdentifierCollection getIdentifierCollection() - { - return mIdentifierCollection; - } - /** * Registers the listener to receive identifier update notifications */ @@ -105,18 +80,27 @@ public void removeIdentifierUpdateListener() } /** - * Provides subclass reference to the decode event broadcaster + * Current collection of identifiers managed by the decoder state. */ - protected Broadcaster getDecodeEventBroadcaster() + public MutableIdentifierCollection getIdentifierCollection() { - return mDecodeEventBroadcaster; + return mIdentifierCollection; } + /** + * Optional current channel descriptor + */ + protected IChannelDescriptor getCurrentChannel() + { + return mCurrentChannel; + } - @Override - public Listener getMessageListener() + /** + * Sets the current channel descriptor + */ + protected void setCurrentChannel(IChannelDescriptor channel) { - return this; + mCurrentChannel = channel; } /** @@ -125,110 +109,28 @@ public Listener getMessageListener() protected void resetState() { mIdentifierCollection.remove(IdentifierClass.USER); - mCurrentChannel = null; } /** * Reset the decoder state to prepare for processing a different sample * source */ - public abstract void reset(); + public void reset() + { + setCurrentChannel(null); + } /** * Allow the decoder to perform any setup actions */ public abstract void init(); - /** - * Implements the IDecoderStateEventListener interface to receive state - * reset events. - */ - public abstract void receiveDecoderStateEvent(DecoderStateEvent event); - /** * Disposes any resources or pointers held by this instance to prepare for * garbage collection */ public void dispose() { - mDecodeEventBroadcaster.dispose(); - mDecodeEventBroadcaster = null; - mDecoderStateListener = null; - } - - /** - * Activity Summary - textual summary of activity observed by the channel state. - */ - public abstract String getActivitySummary(); - - /** - * Broadcasts a decode event to any registered listeners - */ - protected void broadcast(IDecodeEvent event) - { - mDecodeEventBroadcaster.broadcast(event); - } - - /** - * Adds a call event listener - */ - @Override - public void addDecodeEventListener(Listener listener) - { - mDecodeEventBroadcaster.addListener(listener); - } - - /** - * Removes the call event listener - */ - @Override - public void removeDecodeEventListener(Listener listener) - { - mDecodeEventBroadcaster.removeListener(listener); - } - - @Override - public Listener getDecoderStateListener() - { - return mDecoderStateEventListener; - } - - private class DecoderStateEventListener implements Listener - { - @Override - public void receive(DecoderStateEvent event) - { - receiveDecoderStateEvent(event); - } - } - - /** - * Broadcasts a channel state event to any registered listeners - */ - protected void broadcast(DecoderStateEvent event) - { - if(mDecoderStateListener != null) - { - mDecoderStateListener.receive(event); - } - } - - /** - * Adds a decoder state event listener - */ - @Override - public void setDecoderStateListener(Listener listener) - { - mDecoderStateListener = listener; - } - - /** - * Removes the decoder state event listener - */ - @Override - public void removeDecoderStateListener() - { - mDecoderStateListener = null; } /** @@ -244,27 +146,11 @@ public Listener getIdentifierUpdateListener() /** * Configuration identifier listener. */ - public ConfigurationIdentifierListener getConfigurationIdentifierListener() + public Listener getConfigurationIdentifierListener() { return mConfigurationIdentifierListener; } - /** - * Optional current channel descriptor - */ - protected IChannelDescriptor getCurrentChannel() - { - return mCurrentChannel; - } - - /** - * Sets the current channel descriptor - */ - protected void setCurrentChannel(IChannelDescriptor channel) - { - mCurrentChannel = channel; - } - /** * Listener for configuration type identifier updates sent from the channel state. Adds configuration * identifiers to this decoder state so that decode events will contain configuration details in the @@ -275,28 +161,11 @@ public class ConfigurationIdentifierListener implements Listener + * * ***************************************************************************** + * + * + */ + package io.github.dsheirer.channel.state; public class DecoderStateEvent { - private Object mSource; - private Event mEvent; - private State mState; - private long mFrequency; - - public DecoderStateEvent( Object source, Event event, State state ) - { - mSource = source; - mEvent = event; - mState = state; - } - - public DecoderStateEvent( Object source, Event event, State state, long frequency ) - { - this( source, event, state ); - - mFrequency = frequency; - } - - public String toString() - { - StringBuilder sb = new StringBuilder(); - - sb.append( "Decoder State Event - source[" + mSource.getClass() + - "] event[" + mEvent.toString() + - "] state[" + mState.toString() + - "] frequency [" + mFrequency + "]" ); - - return sb.toString(); - } - - public Object getSource() - { - return mSource; - } - - public Event getEvent() - { - return mEvent; - } - - public State getState() - { - return mState; - } - - public long getFrequency() - { - return mFrequency; - } - - public enum Event - { - ALWAYS_UNSQUELCH, - CHANGE_CALL_TIMEOUT, - CONTINUATION, - DECODE, - END, - RESET, - SOURCE_FREQUENCY, - START; - } + private Object mSource; + private Event mEvent; + private State mState; + private int mTimeslot; + private long mFrequency; + + public DecoderStateEvent(Object source, Event event, State state, int timeslot, long frequency) + { + mSource = source; + mEvent = event; + mState = state; + mTimeslot = timeslot; + mFrequency = frequency; + } + + public DecoderStateEvent(Object source, Event event, State state, int timeslot) + { + this(source, event, state, timeslot, 0l); + } + + public DecoderStateEvent(Object source, Event event, State state) + { + this(source, event, state, 0, 0l); + } + + public DecoderStateEvent(Object source, Event event, State state, long frequency) + { + this(source, event, state, 0, frequency); + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + + sb.append("Decoder State Event - source[" + mSource.getClass() + + "] event[" + mEvent.toString() + + "] state[" + mState.toString() + + "] timeslot[" + mTimeslot + + "] frequency [" + mFrequency + "]"); + + return sb.toString(); + } + + public Object getSource() + { + return mSource; + } + + public Event getEvent() + { + return mEvent; + } + + public State getState() + { + return mState; + } + + public long getFrequency() + { + return mFrequency; + } + + public int getTimeslot() + { + return mTimeslot; + } + + public enum Event + { + ALWAYS_UNSQUELCH, + CHANGE_CALL_TIMEOUT, + CONTINUATION, + DECODE, + END, + RESET, + SOURCE_FREQUENCY, + START; + } } \ No newline at end of file diff --git a/src/main/java/io/github/dsheirer/channel/state/IStateMachineListener.java b/src/main/java/io/github/dsheirer/channel/state/IStateMachineListener.java new file mode 100644 index 000000000..9e766c6e8 --- /dev/null +++ b/src/main/java/io/github/dsheirer/channel/state/IStateMachineListener.java @@ -0,0 +1,33 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.channel.state; + +public interface IStateMachineListener +{ + /** + * Indicates that the state has changed for the specified timeslot + * @param state of the state machine currently + * @param timeslot that the state applies to + */ + void stateChanged(State state, int timeslot); +} diff --git a/src/main/java/io/github/dsheirer/channel/state/MultiChannelState.java b/src/main/java/io/github/dsheirer/channel/state/MultiChannelState.java new file mode 100644 index 000000000..3ea1f2dd4 --- /dev/null +++ b/src/main/java/io/github/dsheirer/channel/state/MultiChannelState.java @@ -0,0 +1,576 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.channel.state; + +import io.github.dsheirer.alias.AliasModel; +import io.github.dsheirer.audio.squelch.SquelchStateEvent; +import io.github.dsheirer.channel.metadata.ChannelMetadata; +import io.github.dsheirer.channel.state.DecoderStateEvent.Event; +import io.github.dsheirer.controller.channel.Channel; +import io.github.dsheirer.controller.channel.Channel.ChannelType; +import io.github.dsheirer.controller.channel.ChannelEvent; +import io.github.dsheirer.identifier.IdentifierClass; +import io.github.dsheirer.identifier.IdentifierUpdateListener; +import io.github.dsheirer.identifier.IdentifierUpdateNotification; +import io.github.dsheirer.identifier.MutableIdentifierCollection; +import io.github.dsheirer.identifier.configuration.AliasListConfigurationIdentifier; +import io.github.dsheirer.identifier.configuration.ChannelNameConfigurationIdentifier; +import io.github.dsheirer.identifier.configuration.DecoderTypeConfigurationIdentifier; +import io.github.dsheirer.identifier.configuration.FrequencyConfigurationIdentifier; +import io.github.dsheirer.identifier.configuration.SiteConfigurationIdentifier; +import io.github.dsheirer.identifier.configuration.SystemConfigurationIdentifier; +import io.github.dsheirer.identifier.decoder.ChannelStateIdentifier; +import io.github.dsheirer.module.decode.config.DecodeConfiguration; +import io.github.dsheirer.module.decode.event.IDecodeEvent; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.source.ISourceEventListener; +import io.github.dsheirer.source.SourceEvent; +import io.github.dsheirer.source.SourceType; +import io.github.dsheirer.source.config.SourceConfigTuner; +import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +public class MultiChannelState extends AbstractChannelState implements IDecoderStateEventListener, ISourceEventListener, + IdentifierUpdateListener, IStateMachineListener +{ + private final static Logger mLog = LoggerFactory.getLogger(MultiChannelState.class); + + public static final long FADE_TIMEOUT_DELAY = 1200; + public static final long RESET_TIMEOUT_DELAY = 2000; + + private IdentifierUpdateNotificationProxy mIdentifierUpdateNotificationProxy = new IdentifierUpdateNotificationProxy(); + private DecoderStateEventReceiver mDecoderStateEventReceiver = new DecoderStateEventReceiver(); + private SourceEventListener mInternalSourceEventListener; + private Map mChannelMetadataMap = new TreeMap<>(); + private Map mIdentifierCollectionMap = new TreeMap<>(); + private Map mStateMachineMap = new TreeMap<>(); + private Map mSquelchControllerMap = new TreeMap<>(); + private int mTimeslotCount; + private Listener mIdentifierUpdateListener = new IdentifierUpdateListenerProxy(); + + /** + * Multi-Channel state tracks the overall state of all processing modules and decoders configured for the channel + * and provides squelch control and decoder state reset events. + * + * Uses a state enumeration that defines allowable channel state transitions in order to track a call or data decode + * event from start to finish. Uses a timer to monitor for inactivity and to provide a FADE period that indicates + * to the user that the activity has stopped while continuing to provide details about the call, before the state is + * reset to IDLE. + * + * State Descriptions: + * IDLE: Normal state. No voice or data call activity + * CALL/DATA/ENCRYPTED/CONTROL: Decoding states. + * FADE: The phase after a voice or data call when either an explicit call end has been received, or when no new + * signalling updates have been received, and the fade timer has expired. This phase allows for gui updates to + * signal to the user that the call is ended, while continuing to display the call details for the user + * TEARDOWN: Indicates a traffic channel that will be torn down for reuse. + */ + public MultiChannelState(Channel channel, AliasModel aliasModel, int timeslots) + { + super(channel); + + mTimeslotCount = timeslots; + + for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++) + { + mChannelMetadataMap.put(timeslot, new ChannelMetadata(aliasModel, timeslot)); + MutableIdentifierCollection mutableIdentifierCollection = new MutableIdentifierCollection(timeslot); + mIdentifierCollectionMap.put(timeslot, mutableIdentifierCollection); + + //Set the proxy as a listener so that echo'd updates are broadcast externally + mutableIdentifierCollection.setIdentifierUpdateListener(mIdentifierUpdateNotificationProxy); + + StateMachine stateMachine = new StateMachine(timeslot); + mStateMachineMap.put(timeslot, stateMachine); + stateMachine.addListener(this); + + StateMonitoringSquelchController squelchController = new StateMonitoringSquelchController(timeslot); + mSquelchControllerMap.put(timeslot, squelchController); + stateMachine.addListener(squelchController); + + stateMachine.setChannelType(mChannel.getChannelType()); + stateMachine.setIdentifierUpdateListener(mutableIdentifierCollection); + stateMachine.setEndTimeoutBuffer(RESET_TIMEOUT_DELAY); + if(channel.getChannelType() == ChannelType.STANDARD) + { + stateMachine.setFadeTimeoutBuffer(FADE_TIMEOUT_DELAY); + } + else + { + stateMachine.setFadeTimeoutBuffer(DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS * 1000); + } + } + + createConfigurationIdentifiers(channel); + } + + @Override + public void stateChanged(State state, int timeslot) + { + ChannelStateIdentifier stateIdentifier = ChannelStateIdentifier.create(state); + mIdentifierCollectionMap.get(timeslot).update(stateIdentifier); + mChannelMetadataMap.get(timeslot).receive(new IdentifierUpdateNotification(stateIdentifier, IdentifierUpdateNotification.Operation.ADD, timeslot)); + + switch(state) + { + case IDLE: + broadcast(new DecoderStateEvent(this, Event.RESET, State.IDLE)); + break; + case RESET: + reset(timeslot); + mStateMachineMap.get(timeslot).setState(State.IDLE); + break; + case TEARDOWN: + if(mChannel.isTrafficChannel()) + { + checkTeardown(); + } + else + { + mStateMachineMap.get(timeslot).setState(State.RESET); + } + break; + } + } + + /** + * Checks the state of each timeslot and issues a teardown request if all timeslots are inactive + */ + private void checkTeardown() + { + boolean teardown = true; + + for(StateMachine stateMachine: mStateMachineMap.values()) + { + if(stateMachine.getState().isActiveState()) + { + teardown = false; + } + } + + if(teardown) + { + broadcast(new ChannelEvent(mChannel, ChannelEvent.Event.REQUEST_DISABLE)); + } + } + + @Override + protected void checkState() + { + for(StateMachine stateMachine: mStateMachineMap.values()) + { + stateMachine.checkState(); + } + } + + /** + * Creates configuration identifiers for the channel name, system, site and alias list name. + */ + private void createConfigurationIdentifiers(Channel channel) + { + for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++) + { + MutableIdentifierCollection identifierCollection = mIdentifierCollectionMap.get(timeslot); + + identifierCollection.update(DecoderTypeConfigurationIdentifier.create(channel.getDecodeConfiguration().getDecoderType())); + + if(channel.hasSystem()) + { + identifierCollection.update(SystemConfigurationIdentifier.create(channel.getSystem())); + } + if(channel.hasSite()) + { + identifierCollection.update(SiteConfigurationIdentifier.create(channel.getSite())); + } + if(channel.getName() != null && !channel.getName().isEmpty()) + { + identifierCollection.update(ChannelNameConfigurationIdentifier.create(channel.getName())); + } + if(channel.getAliasListName() != null && !channel.getAliasListName().isEmpty()) + { + identifierCollection.update(AliasListConfigurationIdentifier.create(channel.getAliasListName())); + } + if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER) + { + long frequency = ((SourceConfigTuner)channel.getSourceConfiguration()).getFrequency(); + identifierCollection.update(FrequencyConfigurationIdentifier.create(frequency)); + } + else if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER_MULTIPLE_FREQUENCIES) + { + List frequencies = ((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).getFrequencies(); + + if(frequencies.size() > 0) + { + identifierCollection.update(FrequencyConfigurationIdentifier.create(frequencies.get(0))); + } + } + } + } + + /** + * Interface to receive channel identifier updates from this channel state and from any + * decoder states. + */ + @Override + public Listener getIdentifierUpdateListener() + { + return mIdentifierUpdateListener; + } + + /** + * Registers the external listener that will receive identifier update notifications produced by this channel state + * @param listener + */ + @Override + public void setIdentifierUpdateListener(Listener listener) + { + mIdentifierUpdateNotificationProxy.setListener(listener); + } + + /** + * Unregisters the external listener from receiving identifier update notifications produced by this channel state + */ + @Override + public void removeIdentifierUpdateListener() + { + mIdentifierUpdateNotificationProxy.setListener(null); + } + + /** + * Updates the channel state identifier collection using the update notification. This update will be reflected + * in the internal channel state and will also be broadcast to any listeners, including the channel metadata for + * this channel state. + */ + @Override + public void updateChannelStateIdentifiers(IdentifierUpdateNotification notification) + { + //Explicitly add or remove the identifier from the local identifier collection to allow it to be rebroadcast + //to external listeners, which includes this state's channel metadata + MutableIdentifierCollection identifierCollection = mIdentifierCollectionMap.get(notification.getTimeslot()); + + if(identifierCollection != null) + { + if(notification.isAdd()) + { + identifierCollection.update(notification.getIdentifier()); + } + else if(notification.isSilentAdd()) + { + identifierCollection.silentUpdate(notification.getIdentifier()); + } + else if(notification.isRemove()) + { + identifierCollection.remove(notification.getIdentifier()); + } + else if(notification.isSilentRemove()) + { + identifierCollection.silentRemove(notification.getIdentifier()); + } + } + } + + /** + * Channel metadata for this channel. + */ + public Collection getChannelMetadata() + { + return mChannelMetadataMap.values(); + } + + /** + * Resets this channel state and prepares it for reuse. + */ + @Override + public void reset() + { + for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++) + { + reset(timeslot); + } + + sourceOverflow(false); + } + + private void reset(int timeslot) + { + mStateMachineMap.get(timeslot).setState(State.RESET); + broadcast(new DecoderStateEvent(this, Event.RESET, State.IDLE, timeslot)); + MutableIdentifierCollection identifierCollection = mIdentifierCollectionMap.get(timeslot); + identifierCollection.remove(IdentifierClass.USER); + } + + @Override + public void start() + { + for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++) + { + mIdentifierCollectionMap.get(timeslot).broadcastIdentifiers(); + + if(mChannel.getChannelType() == ChannelType.TRAFFIC) + { + mStateMachineMap.get(timeslot).setState(State.ACTIVE); + } + } + } + + @Override + public void stop() + { + for(StateMonitoringSquelchController squelchController: mSquelchControllerMap.values()) + { + squelchController.setSquelchLock(false); + } + } + + public void dispose() + { + mDecodeEventListener = null; + mDecoderStateListener = null; + } + + @Override + public Listener getSourceEventListener() + { + if(mInternalSourceEventListener == null) + { + mInternalSourceEventListener = new SourceEventListener(); + } + + return mInternalSourceEventListener; + } + + + @Override + public void setSquelchStateListener(Listener listener) + { + for(StateMonitoringSquelchController squelchController: mSquelchControllerMap.values()) + { + squelchController.setSquelchStateListener(listener); + } + } + + @Override + public void removeSquelchStateListener() + { + for(StateMonitoringSquelchController squelchController: mSquelchControllerMap.values()) + { + squelchController.removeSquelchStateListener(); + } + } + + /** + * Broadcasts the source event to a registered external source event listener + */ + protected void broadcast(SourceEvent sourceEvent) + { + if(mExternalSourceEventListener != null) + { + mExternalSourceEventListener.receive(sourceEvent); + } + } + + /** + * Broadcasts the call event to the registered listener + */ + protected void broadcast(IDecodeEvent event) + { + if(mDecodeEventListener != null) + { + mDecodeEventListener.receive(event); + } + } + + /** + * Broadcasts the channel event to a registered listener + */ + private void broadcast(ChannelEvent channelEvent) + { + if(mChannelEventListener != null) + { + mChannelEventListener.receive(channelEvent); + } + } + + /** + * Broadcasts a channel state event to any registered listeners + */ + protected void broadcast(DecoderStateEvent event) + { + if(mDecoderStateListener != null) + { + mDecoderStateListener.receive(event); + } + } + + @Override + public Listener getDecoderStateListener() + { + return mDecoderStateEventReceiver; + } + + /** + * Listener to receive source events. + */ + public class SourceEventListener implements Listener + { + @Override + public void receive(SourceEvent sourceEvent) + { + switch(sourceEvent.getEvent()) + { + case NOTIFICATION_FREQUENCY_CHANGE: + //Rebroadcast source frequency change events for the decoder(s) to process + long frequency = sourceEvent.getValue().longValue(); + + for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++) + { + broadcast(new DecoderStateEvent(this, Event.SOURCE_FREQUENCY, + mStateMachineMap.get(timeslot).getState(), frequency)); + + //Create a new frequency configuration identifier so that downstream consumers receive the change + //via channel metadata and audio packet updates - this is a silent add that is sent as a notification + //to all identifier collections so that they don't rebroadcast the change and cause a feedback loop + + mIdentifierUpdateNotificationProxy.receive(new IdentifierUpdateNotification( + FrequencyConfigurationIdentifier.create(frequency), IdentifierUpdateNotification.Operation.SILENT_ADD, timeslot)); + } + + break; + case NOTIFICATION_MEASURED_FREQUENCY_ERROR: + //Rebroadcast frequency error measurements to external listener if we're currently + //in an active (ie sync locked) state. + for(int timeslot = 0; timeslot < mTimeslotCount; timeslot++) + { + if(mStateMachineMap.get(timeslot).getState().isActiveState()) + { + broadcast(SourceEvent.frequencyErrorMeasurementSyncLocked(sourceEvent.getValue().longValue(), + mChannel.getChannelType().name())); + } + } + break; + } + } + } + + /** + * DecoderStateEvent receiver wrapper + */ + public class DecoderStateEventReceiver implements Listener + { + @Override + public void receive(DecoderStateEvent event) + { + if(event.getSource() != this) + { + switch(event.getEvent()) + { + case ALWAYS_UNSQUELCH: + mSquelchControllerMap.get(event.getTimeslot()).setSquelchLock(true); + break; + case CHANGE_CALL_TIMEOUT: + if(event instanceof ChangeChannelTimeoutEvent) + { + ChangeChannelTimeoutEvent timeout = (ChangeChannelTimeoutEvent)event; + mStateMachineMap.get(event.getTimeslot()).setFadeTimeoutBuffer(timeout.getCallTimeout()); + } + case CONTINUATION: + case DECODE: + case START: + if(State.CALL_STATES.contains(event.getState())) + { + mStateMachineMap.get(event.getTimeslot()).setState(event.getState()); + } + break; + case END: + if(mChannel.isTrafficChannel()) + { + mStateMachineMap.get(event.getTimeslot()).setState(State.TEARDOWN); + } + else + { + mStateMachineMap.get(event.getTimeslot()).setState(State.FADE); + } + break; + case RESET: + /* Channel State does not respond to reset events */ + break; + default: + break; + } + } + } + } + + /** + * Receives and passes identifier update notifications to the correct channel metadata collections + */ + public class IdentifierUpdateListenerProxy implements Listener + { + @Override + public void receive(IdentifierUpdateNotification identifierUpdateNotification) + { + int timeslot = identifierUpdateNotification.getTimeslot(); + + ChannelMetadata channelMetadata = mChannelMetadataMap.get(timeslot); + + if(channelMetadata != null) + { + channelMetadata.receive(identifierUpdateNotification); + } + } + } + + /** + * Proxy between the internal identifier collections and the external update notification listener. This proxy + * enables access to internal components to broadcast silent identifier update notifications externally. + */ + public class IdentifierUpdateNotificationProxy implements Listener + { + private Listener mIdentifierUpdateNotificationListener; + + @Override + public void receive(IdentifierUpdateNotification identifierUpdateNotification) + { + if(mIdentifierUpdateNotificationListener != null) + { + mIdentifierUpdateNotificationListener.receive(identifierUpdateNotification); + } + } + + public void setListener(Listener listener) + { + mIdentifierUpdateNotificationListener = listener; + } + + public void removeListener() + { + mIdentifierUpdateNotificationListener = null; + } + } + +} diff --git a/src/main/java/io/github/dsheirer/channel/state/SingleChannelState.java b/src/main/java/io/github/dsheirer/channel/state/SingleChannelState.java new file mode 100644 index 000000000..cff05d757 --- /dev/null +++ b/src/main/java/io/github/dsheirer/channel/state/SingleChannelState.java @@ -0,0 +1,460 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.channel.state; + +import io.github.dsheirer.alias.AliasModel; +import io.github.dsheirer.audio.squelch.SquelchStateEvent; +import io.github.dsheirer.channel.metadata.ChannelMetadata; +import io.github.dsheirer.channel.state.DecoderStateEvent.Event; +import io.github.dsheirer.controller.channel.Channel; +import io.github.dsheirer.controller.channel.Channel.ChannelType; +import io.github.dsheirer.controller.channel.ChannelEvent; +import io.github.dsheirer.identifier.IdentifierClass; +import io.github.dsheirer.identifier.IdentifierUpdateListener; +import io.github.dsheirer.identifier.IdentifierUpdateNotification; +import io.github.dsheirer.identifier.MutableIdentifierCollection; +import io.github.dsheirer.identifier.configuration.AliasListConfigurationIdentifier; +import io.github.dsheirer.identifier.configuration.ChannelNameConfigurationIdentifier; +import io.github.dsheirer.identifier.configuration.DecoderTypeConfigurationIdentifier; +import io.github.dsheirer.identifier.configuration.FrequencyConfigurationIdentifier; +import io.github.dsheirer.identifier.configuration.SiteConfigurationIdentifier; +import io.github.dsheirer.identifier.configuration.SystemConfigurationIdentifier; +import io.github.dsheirer.identifier.decoder.ChannelStateIdentifier; +import io.github.dsheirer.module.decode.config.DecodeConfiguration; +import io.github.dsheirer.module.decode.event.IDecodeEvent; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.source.ISourceEventListener; +import io.github.dsheirer.source.SourceEvent; +import io.github.dsheirer.source.SourceType; +import io.github.dsheirer.source.config.SourceConfigTuner; +import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Channel state tracks the overall state of all processing modules and decoders configured for the channel and + * provides squelch control and decoder state reset events. + * + * Uses a state enumeration that defines allowable channel state transitions in order to track a call or data decode + * event from start to finish. Uses a timer to monitor for inactivity and to provide a FADE period that indicates + * to the user that the activity has stopped while continuing to provide details about the call, before the state is + * reset to IDLE. + * + * State Descriptions: + * IDLE: Normal state. No voice or data call activity + * CALL/DATA/ENCRYPTED/CONTROL: Decoding states. + * FADE: The phase after a voice or data call when either an explicit call end has been received, or when no new + * signalling updates have been received, and the fade timer has expired. This phase allows for gui updates to + * signal to the user that the call is ended, while continuing to display the call details for the user + * TEARDOWN: Indicates a traffic channel that will be torn down for reuse. + * + * Identifiers and Channel Metadata + * + * The internal identifier collection maintains all of the channel configuration items and monitors source events to + * update the channel's frequency as it changes. These updates are broadcast externally to any identifier collection + * listeners. The internal identifier collection does not listen to incoming identifier update notifications in order + * to prevent a feedback loop. Channel Metadata is the only listener for externally generated updates. + * + * Channel Metadata receives all external identifier notifications and any internal notifications generated by the + * internal identifier collection via feedback. + */ +public class SingleChannelState extends AbstractChannelState implements IDecoderStateEventListener, ISourceEventListener, + IdentifierUpdateListener, IStateMachineListener +{ + private final static Logger mLog = LoggerFactory.getLogger(SingleChannelState.class); + + public static final long FADE_TIMEOUT_DELAY = 1200; + public static final long RESET_TIMEOUT_DELAY = 2000; + + private MutableIdentifierCollection mIdentifierCollection = new MutableIdentifierCollection(); + private IdentifierUpdateNotificationProxy mIdentifierUpdateNotificationProxy = new IdentifierUpdateNotificationProxy(); + private DecoderStateEventReceiver mDecoderStateEventReceiver = new DecoderStateEventReceiver(); + private SourceEventListener mInternalSourceEventListener; + private ChannelMetadata mChannelMetadata; + private StateMachine mStateMachine = new StateMachine(0); + private StateMonitoringSquelchController mSquelchController = new StateMonitoringSquelchController(0); + + public SingleChannelState(Channel channel, AliasModel aliasModel) + { + super(channel); + mChannelMetadata = new ChannelMetadata(aliasModel); + mIdentifierCollection.setIdentifierUpdateListener(mIdentifierUpdateNotificationProxy); + createConfigurationIdentifiers(channel); + + mStateMachine.addListener(this); + mStateMachine.addListener(mSquelchController); + mStateMachine.setChannelType(mChannel.getChannelType()); + mStateMachine.setIdentifierUpdateListener(mIdentifierCollection); + mStateMachine.setEndTimeoutBuffer(RESET_TIMEOUT_DELAY); + if(channel.getChannelType() == ChannelType.STANDARD) + { + mStateMachine.setFadeTimeoutBuffer(FADE_TIMEOUT_DELAY); + } + else + { + mStateMachine.setFadeTimeoutBuffer(DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS * 1000); + } + } + + @Override + public void stateChanged(State state, int timeslot) + { + ChannelStateIdentifier stateIdentifier = ChannelStateIdentifier.create(state); + mIdentifierCollection.update(stateIdentifier); + mChannelMetadata.receive(new IdentifierUpdateNotification(stateIdentifier, IdentifierUpdateNotification.Operation.ADD, timeslot)); + + switch(state) + { + case IDLE: + broadcast(new DecoderStateEvent(this, Event.RESET, State.IDLE)); + break; + case RESET: + reset(); + mStateMachine.setState(State.IDLE); + break; + case TEARDOWN: + if(mChannel.isTrafficChannel()) + { + broadcast(new ChannelEvent(mChannel, ChannelEvent.Event.REQUEST_DISABLE)); + } + else + { + mStateMachine.setState(State.RESET); + } + break; + } + } + + @Override + protected void checkState() + { + mStateMachine.checkState(); + } + + @Override + public void setIdentifierUpdateListener(Listener listener) + { + mIdentifierUpdateNotificationProxy.setListener(listener); + } + + @Override + public void removeIdentifierUpdateListener() + { + mIdentifierUpdateNotificationProxy.removeListener(); + } + + @Override + public void setSquelchStateListener(Listener listener) + { + mSquelchController.setSquelchStateListener(listener); + } + + @Override + public void removeSquelchStateListener() + { + mSquelchController.removeSquelchStateListener(); + } + + /** + * Creates configuration identifiers for the channel name, system, site and alias list name. + */ + private void createConfigurationIdentifiers(Channel channel) + { + mIdentifierCollection.update(DecoderTypeConfigurationIdentifier.create(channel.getDecodeConfiguration().getDecoderType())); + + if(channel.hasSystem()) + { + mIdentifierCollection.update(SystemConfigurationIdentifier.create(channel.getSystem())); + } + if(channel.hasSite()) + { + mIdentifierCollection.update(SiteConfigurationIdentifier.create(channel.getSite())); + } + if(channel.getName() != null && !channel.getName().isEmpty()) + { + mIdentifierCollection.update(ChannelNameConfigurationIdentifier.create(channel.getName())); + } + if(channel.getAliasListName() != null && !channel.getAliasListName().isEmpty()) + { + mIdentifierCollection.update(AliasListConfigurationIdentifier.create(channel.getAliasListName())); + } + if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER) + { + long frequency = ((SourceConfigTuner)channel.getSourceConfiguration()).getFrequency(); + mIdentifierCollection.update(FrequencyConfigurationIdentifier.create(frequency)); + } + else if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER_MULTIPLE_FREQUENCIES) + { + List frequencies = ((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).getFrequencies(); + + if(frequencies.size() > 0) + { + mIdentifierCollection.update(FrequencyConfigurationIdentifier.create(frequencies.get(0))); + } + } + } + + /** + * Interface to receive channel identifier updates from this channel state and from any + * decoder states. + */ + @Override + public Listener getIdentifierUpdateListener() + { + return mChannelMetadata; + } + + /** + * Updates the channel state identifier collection using the update notification. This update will be reflected + * in the internal channel state and will also be broadcast to any listeners, including the channel metadata for + * this channel state. + */ + @Override + public void updateChannelStateIdentifiers(IdentifierUpdateNotification notification) + { + mIdentifierCollection.receive(notification); + mChannelMetadata.receive(notification); + } + + /** + * Channel metadata for this channel. + */ + public Collection getChannelMetadata() + { + return Collections.singletonList(mChannelMetadata); + } + + /** + * Resets this channel state and prepares it for reuse. + */ + @Override + public void reset() + { + mStateMachine.setState(State.RESET); + broadcast(new DecoderStateEvent(this, Event.RESET, State.IDLE)); + mIdentifierCollection.remove(IdentifierClass.USER); + sourceOverflow(false); + } + + @Override + public void start() + { + mIdentifierCollection.broadcastIdentifiers(); + + if(mChannel.getChannelType() == ChannelType.TRAFFIC) + { + mStateMachine.setState(State.ACTIVE); + } + } + + @Override + public void stop() + { + mSquelchController.setSquelchLock(false); + } + + public void dispose() + { + mDecodeEventListener = null; + mDecoderStateListener = null; + } + + @Override + public Listener getSourceEventListener() + { + if(mInternalSourceEventListener == null) + { + mInternalSourceEventListener = new SourceEventListener(); + } + + return mInternalSourceEventListener; + } + + /** + * Broadcasts the source event to a registered external source event listener + */ + protected void broadcast(SourceEvent sourceEvent) + { + if(mExternalSourceEventListener != null) + { + mExternalSourceEventListener.receive(sourceEvent); + } + } + + /** + * Broadcasts the call event to the registered listener + */ + protected void broadcast(IDecodeEvent event) + { + if(mDecodeEventListener != null) + { + mDecodeEventListener.receive(event); + } + } + + /** + * Broadcasts the channel event to a registered listener + */ + private void broadcast(ChannelEvent channelEvent) + { + if(mChannelEventListener != null) + { + mChannelEventListener.receive(channelEvent); + } + } + + /** + * Broadcasts a channel state event to any registered listeners + */ + protected void broadcast(DecoderStateEvent event) + { + if(mDecoderStateListener != null) + { + mDecoderStateListener.receive(event); + } + } + + @Override + public Listener getDecoderStateListener() + { + return mDecoderStateEventReceiver; + } + + /** + * Listener to receive source events. + */ + public class SourceEventListener implements Listener + { + @Override + public void receive(SourceEvent sourceEvent) + { + switch(sourceEvent.getEvent()) + { + case NOTIFICATION_FREQUENCY_CHANGE: + //Rebroadcast source frequency change events for the decoder(s) to process + long frequency = sourceEvent.getValue().longValue(); + broadcast(new DecoderStateEvent(this, Event.SOURCE_FREQUENCY, mStateMachine.getState(), frequency)); + + //Create a new frequency configuration identifier so that downstream consumers receive the change + //via channel metadata and audio packet updates - this is a silent add that is sent as a notification + //to all identifier collections so that they don't rebroadcast the change and cause a feedback loop + mIdentifierUpdateNotificationProxy.receive(new IdentifierUpdateNotification( + FrequencyConfigurationIdentifier.create(frequency), IdentifierUpdateNotification.Operation.SILENT_ADD, 0)); + break; + case NOTIFICATION_MEASURED_FREQUENCY_ERROR: + //Rebroadcast frequency error measurements to external listener if we're currently + //in an active (ie sync locked) state. + if(mStateMachine.getState().isActiveState()) + { + broadcast(SourceEvent.frequencyErrorMeasurementSyncLocked(sourceEvent.getValue().longValue(), + mChannel.getChannelType().name())); + } + break; + } + } + } + + /** + * DecoderStateEvent receiver wrapper + */ + public class DecoderStateEventReceiver implements Listener + { + @Override + public void receive(DecoderStateEvent event) + { + if(event.getSource() != this) + { + switch(event.getEvent()) + { + case ALWAYS_UNSQUELCH: + mSquelchController.setSquelchLock(true); + break; + case CHANGE_CALL_TIMEOUT: + if(event instanceof ChangeChannelTimeoutEvent) + { + ChangeChannelTimeoutEvent timeout = (ChangeChannelTimeoutEvent)event; + mStateMachine.setFadeTimeoutBuffer(timeout.getCallTimeout()); + } + case CONTINUATION: + case DECODE: + case START: + if(State.CALL_STATES.contains(event.getState())) + { + mStateMachine.setState(event.getState()); + } + break; + case END: + if(mChannel.isTrafficChannel()) + { + mStateMachine.setState(State.TEARDOWN); + } + else + { + mStateMachine.setState(State.FADE); + } + break; + case RESET: + /* Channel State does not respond to reset events */ + break; + default: + break; + } + } + } + } + + //TODO: this can probably be removed. The only reason it exists is so that we can inject frequency change + //updates directly to the external broadcaster as a silent add. Otherwise, we could simply register the external + //listener directly on the identifier collection. + + /** + * Proxy between the internal identifier collection and the external update notification listener. This proxy + * enables access to internal components to broadcast silent identifier update notifications externally. + */ + public class IdentifierUpdateNotificationProxy implements Listener + { + private Listener mIdentifierUpdateNotificationListener; + + @Override + public void receive(IdentifierUpdateNotification identifierUpdateNotification) + { + if(mIdentifierUpdateNotificationListener != null) + { + mIdentifierUpdateNotificationListener.receive(identifierUpdateNotification); + } + } + + public void setListener(Listener listener) + { + mIdentifierUpdateNotificationListener = listener; + } + + public void removeListener() + { + mIdentifierUpdateNotificationListener = null; + } + } +} diff --git a/src/main/java/io/github/dsheirer/channel/state/State.java b/src/main/java/io/github/dsheirer/channel/state/State.java index e88b697fb..63b356d23 100644 --- a/src/main/java/io/github/dsheirer/channel/state/State.java +++ b/src/main/java/io/github/dsheirer/channel/state/State.java @@ -1,20 +1,24 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014-2016 Dennis Sheirer +/* * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - ******************************************************************************/ + */ package io.github.dsheirer.channel.state; import java.util.EnumSet; @@ -39,7 +43,8 @@ public boolean canChangeTo(State state) state == DATA || state == ENCRYPTED || state == FADE || - state == TEARDOWN; + state == TEARDOWN || + state == RESET; } }, /** @@ -55,7 +60,8 @@ public boolean canChangeTo(State state) state == DATA || state == ENCRYPTED || state == FADE || - state == TEARDOWN; + state == TEARDOWN || + state == RESET; } }, /** @@ -67,7 +73,8 @@ public boolean canChangeTo(State state) public boolean canChangeTo(State state) { return state == IDLE || - state == FADE; + state == FADE || + state == RESET; } }, /** @@ -83,6 +90,7 @@ public boolean canChangeTo(State state) state == CONTROL || state == ENCRYPTED || state == FADE || + state == RESET || state == TEARDOWN; } }, @@ -95,7 +103,8 @@ public boolean canChangeTo(State state) public boolean canChangeTo(State state) { return state == FADE || - state == TEARDOWN; + state == TEARDOWN || + state == RESET; } }, /** diff --git a/src/main/java/io/github/dsheirer/channel/state/StateMachine.java b/src/main/java/io/github/dsheirer/channel/state/StateMachine.java new file mode 100644 index 000000000..c08bf1b2a --- /dev/null +++ b/src/main/java/io/github/dsheirer/channel/state/StateMachine.java @@ -0,0 +1,214 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.channel.state; + +import io.github.dsheirer.controller.channel.Channel; +import io.github.dsheirer.identifier.IdentifierUpdateNotification; +import io.github.dsheirer.identifier.decoder.ChannelStateIdentifier; +import io.github.dsheirer.sample.Listener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +public class StateMachine +{ + private final static Logger mLog = LoggerFactory.getLogger(StateMachine.class); + + protected State mState = State.IDLE; + protected long mFadeTimeout; + protected long mFadeTimeoutBuffer = 0; + protected long mEndTimeout; + protected long mEndTimeoutBuffer = 0; + private int mTimeslot; + private Channel.ChannelType mChannelType = Channel.ChannelType.STANDARD; + private List mStateMachineListeners = new ArrayList<>(); + private Listener mIdentifierUpdateListener; + + public StateMachine(int timeslot) + { + mTimeslot = timeslot; + } + + public void addListener(IStateMachineListener listener) + { + mStateMachineListeners.add(listener); + } + + public void removeListener(IStateMachineListener listener) + { + mStateMachineListeners.remove(listener); + } + + public void setIdentifierUpdateListener(Listener listener) + { + mIdentifierUpdateListener = listener; + } + + public void setChannelType(Channel.ChannelType channelType) + { + mChannelType = channelType; + } + + public void checkState() + { + if(mState.isActiveState() && mFadeTimeout <= System.currentTimeMillis()) + { + setState(State.FADE); + } + else if(mState == State.FADE && mEndTimeout <= System.currentTimeMillis()) + { + setState(State.TEARDOWN); + } + } + + public State getState() + { + return mState; + } + + public void setState(State state) + { + if(state == mState) + { + if(State.CALL_STATES.contains(state)) + { + updateFadeTimeout(); + } + } + else if(mState.canChangeTo(state)) + { + switch(state) + { + case ACTIVE: + mState = state; + updateFadeTimeout(); + broadcast(ChannelStateIdentifier.ACTIVE); + break; + case CONTROL: + //Don't allow traffic channels to be control channels, otherwise they can't transition to teardown + if(mChannelType == Channel.ChannelType.STANDARD) + { + mState = state; + updateFadeTimeout(); + broadcast(ChannelStateIdentifier.CONTROL); + } + break; + case DATA: + mState = state; + updateFadeTimeout(); + broadcast(ChannelStateIdentifier.DATA); + break; + case ENCRYPTED: + mState = state; + updateFadeTimeout(); + broadcast(ChannelStateIdentifier.ENCRYPTED); + break; + case CALL: + mState = state; + updateFadeTimeout(); + broadcast(ChannelStateIdentifier.CALL); + break; + case FADE: + mState = state; + broadcast(ChannelStateIdentifier.FADE); + break; + case IDLE: + mState = state; + broadcast(ChannelStateIdentifier.IDLE); + break; + case TEARDOWN: + mState = state; + broadcast(ChannelStateIdentifier.TEARDOWN); + break; + case RESET: + mState = State.RESET; + broadcast(ChannelStateIdentifier.RESET); + break; + default: + break; + } + + //If the state successfully changed to the new state, announce it + if(mState == state) + { + for(IStateMachineListener listener: mStateMachineListeners) + { + listener.stateChanged(mState, mTimeslot); + } + } + } + } + + private void broadcast(ChannelStateIdentifier channelStateIdentifier) + { + if(mIdentifierUpdateListener != null) + { + mIdentifierUpdateListener.receive(new IdentifierUpdateNotification(channelStateIdentifier, + IdentifierUpdateNotification.Operation.ADD, mTimeslot)); + } + } + + private void updateFadeTimeout() + { + mFadeTimeout = System.currentTimeMillis() + mFadeTimeoutBuffer; + } + + public void setFadeTimeout(long timeout) + { + mFadeTimeout = timeout; + } + + public long getFadeTimeout() + { + return mFadeTimeout; + } + + public void setFadeTimeoutBuffer(long buffer) + { + mFadeTimeoutBuffer = buffer; + updateFadeTimeout(); + } + + private void updateEndTimeout() + { + mEndTimeout = System.currentTimeMillis() + mEndTimeoutBuffer; + } + + public void setEndTimeoutBuffer(long buffer) + { + mEndTimeoutBuffer = buffer; + updateEndTimeout(); + } + + public void setEndTimeout(long endTimeout) + { + mEndTimeout = endTimeout; + } + + public long getEndTimeout() + { + return mEndTimeout; + } +} diff --git a/src/main/java/io/github/dsheirer/channel/state/StateMonitoringSquelchController.java b/src/main/java/io/github/dsheirer/channel/state/StateMonitoringSquelchController.java new file mode 100644 index 000000000..68ae350c2 --- /dev/null +++ b/src/main/java/io/github/dsheirer/channel/state/StateMonitoringSquelchController.java @@ -0,0 +1,86 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.channel.state; + +import io.github.dsheirer.audio.squelch.ISquelchStateProvider; +import io.github.dsheirer.audio.squelch.SquelchState; +import io.github.dsheirer.audio.squelch.SquelchStateEvent; +import io.github.dsheirer.sample.Listener; + +public class StateMonitoringSquelchController implements IStateMachineListener, ISquelchStateProvider +{ + private boolean mSquelchLocked; + private SquelchState mSquelchState = SquelchState.SQUELCH; + private Listener mSquelchStateListener; + private int mTimeslot; + + public StateMonitoringSquelchController(int timeslot) + { + mTimeslot = timeslot; + } + + public void setSquelchStateListener(Listener listener) + { + mSquelchStateListener = listener; + } + + public void removeSquelchStateListener() + { + mSquelchStateListener = null; + } + + public void setSquelchLock(boolean locked) + { + mSquelchLocked = locked; + setSquelchState(mSquelchLocked ? SquelchState.UNSQUELCH : SquelchState.SQUELCH); + } + + private void setSquelchState(SquelchState squelchState) + { + if(mSquelchState != squelchState) + { + mSquelchState = squelchState; + + if(mSquelchStateListener != null) + { + mSquelchStateListener.receive(new SquelchStateEvent(squelchState, mTimeslot)); + } + } + } + + @Override + public void stateChanged(State state, int timeslot) + { + if(!mSquelchLocked) + { + if(state == State.CALL) + { + setSquelchState(SquelchState.UNSQUELCH); + } + else + { + setSquelchState(SquelchState.SQUELCH); + } + } + } +} diff --git a/src/main/java/io/github/dsheirer/channel/state/TimeslotDecoderState.java b/src/main/java/io/github/dsheirer/channel/state/TimeslotDecoderState.java new file mode 100644 index 000000000..622606bfb --- /dev/null +++ b/src/main/java/io/github/dsheirer/channel/state/TimeslotDecoderState.java @@ -0,0 +1,92 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.channel.state; + +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Form; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.IdentifierClass; +import io.github.dsheirer.identifier.IdentifierUpdateNotification; +import io.github.dsheirer.identifier.MutableIdentifierCollection; +import io.github.dsheirer.identifier.configuration.ChannelDescriptorConfigurationIdentifier; +import io.github.dsheirer.sample.Listener; + +public abstract class TimeslotDecoderState extends DecoderState +{ + private int mTimeslot; + + public TimeslotDecoderState(int timeslot) + { + super(new MutableIdentifierCollection(timeslot)); + mTimeslot = timeslot; + mConfigurationIdentifierListener = new TimeslotConfigurationIdentifierListener(); + } + + protected int getTimeslot() + { + return mTimeslot; + } + + /** + * Listener for configuration type identifier updates sent from the channel state. Adds configuration + * identifiers to this decoder state so that decode events will contain configuration details in the + * event's identifier collection. + */ + public class TimeslotConfigurationIdentifierListener implements Listener + { + @Override + public void receive(IdentifierUpdateNotification identifierUpdateNotification) + { + if(identifierUpdateNotification.getTimeslot() == getTimeslot()) + { + if(identifierUpdateNotification.getIdentifier().getIdentifierClass() == IdentifierClass.CONFIGURATION && + identifierUpdateNotification.getIdentifier().getForm() != Form.DECODER_TYPE && + identifierUpdateNotification.getIdentifier().getForm() != Form.CHANNEL_DESCRIPTOR) + { + if(identifierUpdateNotification.isAdd()) + { + getIdentifierCollection().update(identifierUpdateNotification.getIdentifier()); + } + else if(identifierUpdateNotification.isSilentAdd()) + { + getIdentifierCollection().silentUpdate(identifierUpdateNotification.getIdentifier()); + } + } + + if(identifierUpdateNotification.getOperation() == IdentifierUpdateNotification.Operation.ADD) + { + Identifier identifier = identifierUpdateNotification.getIdentifier(); + + if(identifier instanceof ChannelDescriptorConfigurationIdentifier) + { + setCurrentChannel(((ChannelDescriptorConfigurationIdentifier)identifier).getValue()); + } + else if(identifier instanceof IChannelDescriptor) + { + setCurrentChannel((IChannelDescriptor)identifier); + } + } + } + } + } +} diff --git a/src/main/java/io/github/dsheirer/controller/ControllerPanel.java b/src/main/java/io/github/dsheirer/controller/ControllerPanel.java index 3d8fb5f39..248073290 100644 --- a/src/main/java/io/github/dsheirer/controller/ControllerPanel.java +++ b/src/main/java/io/github/dsheirer/controller/ControllerPanel.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.controller; @@ -35,6 +37,7 @@ import io.github.dsheirer.map.MapPanel; import io.github.dsheirer.map.MapService; import io.github.dsheirer.preference.UserPreferences; +import io.github.dsheirer.record.RecorderManager; import io.github.dsheirer.settings.SettingsManager; import io.github.dsheirer.source.SourceManager; import io.github.dsheirer.source.tuner.TunerModel; @@ -64,7 +67,8 @@ public class ControllerPanel extends JPanel public ControllerPanel(AudioPlaybackManager audioPlaybackManager, AliasModel aliasModel, BroadcastModel broadcastModel, ChannelModel channelModel, ChannelMapModel channelMapModel, ChannelProcessingManager channelProcessingManager, IconManager iconManager, MapService mapService, SettingsManager settingsManager, - SourceManager sourceManager, TunerModel tunerModel, UserPreferences userPreferences) + SourceManager sourceManager, TunerModel tunerModel, UserPreferences userPreferences, + RecorderManager recorderManager) { mBroadcastModel = broadcastModel; mChannelModel = channelModel; @@ -84,7 +88,7 @@ public ControllerPanel(AudioPlaybackManager audioPlaybackManager, AliasModel ali mAliasController = new AliasController(aliasModel, broadcastModel, iconManager, userPreferences); - mTunerManagerPanel = new TunerViewPanel(tunerModel, userPreferences); + mTunerManagerPanel = new TunerViewPanel(tunerModel, userPreferences, recorderManager); init(); } diff --git a/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java b/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java index 3aa568992..8e738d4d8 100644 --- a/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java +++ b/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java @@ -1,34 +1,38 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.controller.channel; import io.github.dsheirer.alias.AliasModel; import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.channel.metadata.ChannelMetadata; import io.github.dsheirer.channel.metadata.ChannelMetadataModel; import io.github.dsheirer.controller.channel.map.ChannelMapModel; import io.github.dsheirer.filter.FilterSet; +import io.github.dsheirer.identifier.Form; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.identifier.IdentifierClass; import io.github.dsheirer.identifier.IdentifierCollection; import io.github.dsheirer.identifier.IdentifierUpdateNotification; -import io.github.dsheirer.identifier.configuration.ChannelDescriptorConfigurationIdentifier; +import io.github.dsheirer.identifier.decoder.DecoderLogicalChannelNameIdentifier; import io.github.dsheirer.message.IMessage; import io.github.dsheirer.module.Module; import io.github.dsheirer.module.ProcessingChain; @@ -37,9 +41,8 @@ import io.github.dsheirer.module.decode.event.MessageActivityModel; import io.github.dsheirer.module.log.EventLogManager; import io.github.dsheirer.preference.UserPreferences; +import io.github.dsheirer.record.RecorderFactory; import io.github.dsheirer.record.RecorderManager; -import io.github.dsheirer.record.RecorderType; -import io.github.dsheirer.record.binary.BinaryRecorder; import io.github.dsheirer.sample.Broadcaster; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.buffer.ReusableAudioPacket; @@ -237,8 +240,8 @@ private void startProcessing(ChannelEvent event) { channel.setProcessing(false); - mChannelEventBroadcaster.broadcast(new ChannelEvent(channel, ChannelEvent.Event.NOTIFICATION_PROCESSING_START_REJECTED, - TUNER_UNAVAILABLE_DESCRIPTION)); + mChannelEventBroadcaster.broadcast(new ChannelEvent(channel, + ChannelEvent.Event.NOTIFICATION_PROCESSING_START_REJECTED, TUNER_UNAVAILABLE_DESCRIPTION)); return; } @@ -285,43 +288,10 @@ private void startProcessing(ChannelEvent event) processingChain.addModules(loggers); } - /* Setup recorders */ - List recorders = channel.getRecordConfiguration().getRecorders(); - - if(!recorders.isEmpty()) - { - /* Add baseband recorder */ - if((recorders.contains(RecorderType.BASEBAND) && channel.getChannelType() == Channel.ChannelType.STANDARD)) - { - processingChain.addModule(mRecorderManager.getBasebandRecorder(channel.toString())); - } - - /* Add traffic channel baseband recorder */ - if(recorders.contains(RecorderType.TRAFFIC_BASEBAND) && channel.getChannelType() == Channel.ChannelType.TRAFFIC) - { - processingChain.addModule(mRecorderManager.getBasebandRecorder(channel.toString())); - } - - /* Add decoded bit stream recorder if the decoder supports bitstream output */ - if(DecoderFactory.getBitstreamDecoders().contains(channel.getDecodeConfiguration().getDecoderType())) - { - if((recorders.contains(RecorderType.DEMODULATED_BIT_STREAM) && - channel.getChannelType() == Channel.ChannelType.STANDARD)) - { - processingChain.addModule(new BinaryRecorder(mRecorderManager.getRecordingBasePath(), - channel.toString(), channel.getDecodeConfiguration().getDecoderType().getProtocol())); - } - - /* Add traffic channel decoded bit stream recorder */ - if(recorders.contains(RecorderType.TRAFFIC_DEMODULATED_BIT_STREAM) && - channel.getChannelType() == Channel.ChannelType.TRAFFIC) - { - processingChain.addModule(new BinaryRecorder(mRecorderManager.getRecordingBasePath(), - channel.toString(), channel.getDecodeConfiguration().getDecoderType().getProtocol())); - } - } - } + //Add recorders + processingChain.addModules(RecorderFactory.getRecorders(mRecorderManager, mUserPreferences, channel)); + //Set the samples source processingChain.setSource(source); //Inject the channel identifier for traffic channels and preload user identifiers @@ -330,22 +300,47 @@ private void startProcessing(ChannelEvent event) ChannelGrantEvent channelGrantEvent = (ChannelGrantEvent)event; IChannelDescriptor channelDescriptor = channelGrantEvent.getChannelDescriptor(); + IdentifierCollection identifierCollection = channelGrantEvent.getIdentifierCollection(); + if(channelDescriptor != null) { - ChannelDescriptorConfigurationIdentifier identifier = new ChannelDescriptorConfigurationIdentifier(channelDescriptor); - IdentifierUpdateNotification notification = new IdentifierUpdateNotification(identifier, - IdentifierUpdateNotification.Operation.ADD); - processingChain.getChannelState().updateChannelStateIdentifiers(notification); + for(int timeslot = 0; timeslot < channelDescriptor.getTimeslotCount(); timeslot++) + { + DecoderLogicalChannelNameIdentifier identifier = + DecoderLogicalChannelNameIdentifier.create(channelDescriptor.toString(), channelDescriptor.getProtocol()); + IdentifierUpdateNotification notification = new IdentifierUpdateNotification(identifier, + IdentifierUpdateNotification.Operation.ADD, timeslot); + processingChain.getChannelState().updateChannelStateIdentifiers(notification); + + //Inject scramble parameters + for(Identifier scrambleParameters: identifierCollection.getIdentifiers(Form.SCRAMBLE_PARAMETERS)) + { + //Broadcast scramble parameters to both timeslots + IdentifierUpdateNotification scrambleNotification = new IdentifierUpdateNotification(scrambleParameters, + IdentifierUpdateNotification.Operation.ADD, timeslot); + processingChain.getChannelState().updateChannelStateIdentifiers(scrambleNotification); + } + } } - IdentifierCollection identifierCollection = channelGrantEvent.getIdentifierCollection(); - for(Identifier userIdentifier : identifierCollection.getIdentifiers(IdentifierClass.USER)) { - IdentifierUpdateNotification notification = new IdentifierUpdateNotification(userIdentifier, - IdentifierUpdateNotification.Operation.ADD); - processingChain.getChannelState().updateChannelStateIdentifiers(notification); + if(channelDescriptor.getTimeslotCount() > 1) + { + //Only broadcast an identifier update for the timeslot specified in the originating collection + IdentifierUpdateNotification notification = new IdentifierUpdateNotification(userIdentifier, + IdentifierUpdateNotification.Operation.ADD, channelGrantEvent.getIdentifierCollection().getTimeslot()); + processingChain.getChannelState().updateChannelStateIdentifiers(notification); + } + else + { + //Only broadcast an identifier update for the timeslot specified in the originating collection + IdentifierUpdateNotification notification = new IdentifierUpdateNotification(userIdentifier, + IdentifierUpdateNotification.Operation.ADD, 0); + processingChain.getChannelState().updateChannelStateIdentifiers(notification); + } } + } processingChain.start(); @@ -372,7 +367,10 @@ private void stopProcessing(Channel channel, boolean remove) { ProcessingChain processingChain = mProcessingChains.get(channel); - getChannelMetadataModel().remove(processingChain.getChannelState().getChannelMetadata()); + for(ChannelMetadata channelMetadata: processingChain.getChannelState().getChannelMetadata()) + { + getChannelMetadataModel().remove(channelMetadata); + } processingChain.stop(); diff --git a/src/main/java/io/github/dsheirer/dsp/filter/design/FilterViewer.java b/src/main/java/io/github/dsheirer/dsp/filter/design/FilterViewer.java index 8cabd5ace..eaaf131b9 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/design/FilterViewer.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/design/FilterViewer.java @@ -1,3 +1,25 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + package io.github.dsheirer.dsp.filter.design; import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification; @@ -62,13 +84,12 @@ private float[] getFilter() // .build(); FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder() - .sampleRate(25000.0) - .gridDensity(16) - .passBandCutoff(11800) + .sampleRate(50000.0) + .passBandCutoff(6500) .passBandAmplitude(1.0) - .passBandRipple(0.01) - .stopBandStart(12400) + .passBandRipple(0.005) .stopBandAmplitude(0.0) + .stopBandStart(7200) .stopBandRipple(0.01) .build(); diff --git a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedDemodulatorInstrumented.java b/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedDemodulatorInstrumented.java index 819a91249..4543f0d6f 100644 --- a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedDemodulatorInstrumented.java +++ b/src/main/java/io/github/dsheirer/dsp/psk/DQPSKDecisionDirectedDemodulatorInstrumented.java @@ -1,23 +1,30 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.dsp.psk; import io.github.dsheirer.dsp.psk.pll.CostasLoop; import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop; import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.Complex; public class DQPSKDecisionDirectedDemodulatorInstrumented extends DQPSKDecisionDirectedDemodulator @@ -27,6 +34,7 @@ public class DQPSKDecisionDirectedDemodulatorInstrumented extends DQPSKDecisionD private Listener mComplexSymbolListener; private Listener mPLLErrorListener; private Listener mPLLFrequencyListener; + private Listener mFilteredGainAppliedComplexBufferListener; private double mSampleRate; /** @@ -48,6 +56,18 @@ public DQPSKDecisionDirectedDemodulatorInstrumented(IPhaseLockedLoop phaseLocked mSampleRate = sampleRate; } + @Override + public void receive(ReusableComplexBuffer reusableComplexBuffer) + { + if(mFilteredGainAppliedComplexBufferListener != null) + { + reusableComplexBuffer.incrementUserCount(); + mFilteredGainAppliedComplexBufferListener.receive(reusableComplexBuffer); + } + + super.receive(reusableComplexBuffer); + } + /** * Overrides the parent class symbol calculation to capture eye diagram data */ @@ -128,4 +148,11 @@ public void setPLLFrequencyListener(Listener listener) mPLLFrequencyListener = listener; } + /** + * Regsiters the listener to receive complex sample buffers that have been filtered with automatic gain control applied + */ + public void setFilteredGainAppliedComplexBufferListener(Listener listener) + { + mFilteredGainAppliedComplexBufferListener = listener; + } } diff --git a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKGardnerDemodulatorInstrumented.java b/src/main/java/io/github/dsheirer/dsp/psk/DQPSKGardnerDemodulatorInstrumented.java index 272b05342..2e7399145 100644 --- a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKGardnerDemodulatorInstrumented.java +++ b/src/main/java/io/github/dsheirer/dsp/psk/DQPSKGardnerDemodulatorInstrumented.java @@ -1,23 +1,30 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.dsp.psk; import io.github.dsheirer.dsp.psk.pll.CostasLoop; import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop; import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.Complex; public class DQPSKGardnerDemodulatorInstrumented extends DQPSKGardnerDemodulator @@ -27,6 +34,7 @@ public class DQPSKGardnerDemodulatorInstrumented extends DQPSKGardnerDemodulator private Listener mComplexSymbolListener; private Listener mPLLErrorListener; private Listener mPLLFrequencyListener; + private Listener mFilteredGainAppliedComplexBufferListener; private double mSampleRate; /** @@ -45,6 +53,18 @@ public DQPSKGardnerDemodulatorInstrumented(IPhaseLockedLoop phaseLockedLoop, mSampleRate = sampleRate; } + @Override + public void receive(ReusableComplexBuffer reusableComplexBuffer) + { + if(mFilteredGainAppliedComplexBufferListener != null) + { + reusableComplexBuffer.incrementUserCount(); + mFilteredGainAppliedComplexBufferListener.receive(reusableComplexBuffer); + } + + super.receive(reusableComplexBuffer); + } + /** * Overrides the parent class symbol calculation to capture eye diagram data */ @@ -124,4 +144,12 @@ public void setPLLFrequencyListener(Listener listener) { mPLLFrequencyListener = listener; } + + /** + * Registers the listener to receive complex sample buffers that have been filtered with automatic gain control applied + */ + public void setFilteredGainAppliedComplexBufferListener(Listener listener) + { + mFilteredGainAppliedComplexBufferListener = listener; + } } diff --git a/src/main/java/io/github/dsheirer/dsp/psk/InterpolatingSampleBuffer.java b/src/main/java/io/github/dsheirer/dsp/psk/InterpolatingSampleBuffer.java index 37ea8fe95..bdf6e817b 100644 --- a/src/main/java/io/github/dsheirer/dsp/psk/InterpolatingSampleBuffer.java +++ b/src/main/java/io/github/dsheirer/dsp/psk/InterpolatingSampleBuffer.java @@ -1,34 +1,43 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.dsp.psk; import io.github.dsheirer.dsp.filter.interpolator.RealInterpolator; import io.github.dsheirer.sample.complex.Complex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class InterpolatingSampleBuffer { + private final static Logger mLog = LoggerFactory.getLogger(InterpolatingSampleBuffer.class); private static final float MAXIMUM_DEVIATION_SAMPLES_PER_SYMBOL = 0.02f; // +/- 2% deviation private Complex mPrecedingSample = new Complex(0,0); private Complex mCurrentSample = new Complex(0,0); private Complex mMiddleSample = new Complex(0,0); - private float[] mDelayLineInphase; - private float[] mDelayLineQuadrature; - private int mDelayLinePointer = 0; + protected float[] mDelayLineInphase; + protected float[] mDelayLineQuadrature; + protected int mDelayLinePointer = 0; private int mTwiceSamplesPerSymbol; private float mSamplingPoint; diff --git a/src/main/java/io/github/dsheirer/dsp/psk/InterpolatingSampleBufferInstrumented.java b/src/main/java/io/github/dsheirer/dsp/psk/InterpolatingSampleBufferInstrumented.java index dcdef3998..610e9ac01 100644 --- a/src/main/java/io/github/dsheirer/dsp/psk/InterpolatingSampleBufferInstrumented.java +++ b/src/main/java/io/github/dsheirer/dsp/psk/InterpolatingSampleBufferInstrumented.java @@ -1,36 +1,54 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.dsp.psk; import io.github.dsheirer.sample.complex.Complex; +import io.github.dsheirer.sample.complex.ComplexSampleListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class InterpolatingSampleBufferInstrumented extends InterpolatingSampleBuffer { + private final static Logger mLog = LoggerFactory.getLogger(InterpolatingSampleBufferInstrumented.class); private SymbolDecisionData mSymbolDecisionData; + private ComplexSampleListener mSampleListener; + private int mBufferLength; public InterpolatingSampleBufferInstrumented(float samplesPerSymbol, float symbolTimingGain) { super(samplesPerSymbol, symbolTimingGain); - mSymbolDecisionData = new SymbolDecisionData((int)samplesPerSymbol); + mBufferLength = (int)Math.ceil(samplesPerSymbol); + mSymbolDecisionData = new SymbolDecisionData(mBufferLength); } public void receive(Complex sample) { super.receive(sample); mSymbolDecisionData.receive(sample); + + if(mSampleListener != null) + { + mSampleListener.receive(sample.inphase(), sample.quadrature()); + } } /** @@ -40,8 +58,22 @@ public void receive(Complex sample) */ public SymbolDecisionData getSymbolDecisionData() { + for(int x = mDelayLinePointer; x < mDelayLinePointer + mBufferLength; x++) + { + mSymbolDecisionData.receive(mDelayLineInphase[x], mDelayLineQuadrature[x]); + } + mSymbolDecisionData.setSamplingPoint(getSamplingPoint()); return mSymbolDecisionData; } + /** + * Sets the listener to receive samples being sent to this buffer. Note: these samples have + * already been corrected by the PLL, so this provides an ideal tap point for PLL corrected samples. + * @param listener to receive samples. + */ + public void setSampleListener(ComplexSampleListener listener) + { + mSampleListener = listener; + } } diff --git a/src/main/java/io/github/dsheirer/dsp/psk/SymbolDecisionData.java b/src/main/java/io/github/dsheirer/dsp/psk/SymbolDecisionData.java index e06f3d22d..b2dd87f2d 100644 --- a/src/main/java/io/github/dsheirer/dsp/psk/SymbolDecisionData.java +++ b/src/main/java/io/github/dsheirer/dsp/psk/SymbolDecisionData.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.dsp.psk; import io.github.dsheirer.buffer.ComplexCircularBuffer; @@ -25,14 +31,16 @@ public class SymbolDecisionData private ComplexCircularBuffer mBuffer; private float mSamplingPoint; + private float mSamplesPerSymbol; /** * Circular buffer for capturing two symbols worth of sample data for use in instrumentation. * @param samplesPerSymbol to size the buffer */ - public SymbolDecisionData(int samplesPerSymbol) + public SymbolDecisionData(float samplesPerSymbol) { - mBuffer = new ComplexCircularBuffer(2 * samplesPerSymbol); + mSamplesPerSymbol = samplesPerSymbol; + mBuffer = new ComplexCircularBuffer(8); } /** @@ -68,7 +76,20 @@ public float getSamplingPoint() } /** - * Array of demodulated samples representing the current symbol where each current sample is demodulated against + * Raw samples + */ + public Complex[] getSamples() + { + return mBuffer.getAll(); + } + + public Complex[] getSamples(int length) + { + return mBuffer.get(length); + } + + /** + * Array of (FM) demodulated samples representing the current symbol where each current sample is demodulated against * the previous symbol's sample to produce the differential demodulated sample. Samples are in time order. * * Note: differential decoding is on an integral samples-per-symbol basis and does not use fractional interpolation. diff --git a/src/main/java/io/github/dsheirer/dsp/psk/pll/AdaptivePLLGainMonitor.java b/src/main/java/io/github/dsheirer/dsp/psk/pll/AdaptivePLLGainMonitor.java index 6b94d6777..15db89bb7 100644 --- a/src/main/java/io/github/dsheirer/dsp/psk/pll/AdaptivePLLGainMonitor.java +++ b/src/main/java/io/github/dsheirer/dsp/psk/pll/AdaptivePLLGainMonitor.java @@ -1,22 +1,26 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ package io.github.dsheirer.dsp.psk.pll; import io.github.dsheirer.dsp.symbol.ISyncDetectListener; -import io.github.dsheirer.module.decode.p25.P25Decoder; +import io.github.dsheirer.module.decode.p25.phase1.P25P1Decoder; import io.github.dsheirer.source.SourceEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,7 +34,7 @@ public class AdaptivePLLGainMonitor implements ISyncDetectListener, IFrequencyEr private static final int MAX_SYNC_COUNT = 6; private CostasLoop mCostasLoop; - private P25Decoder mP25Decoder; + private P25P1Decoder mP25P1Decoder; private PLLGain mPLLGain = PLLGain.LEVEL_1; private int mSyncCount; @@ -39,14 +43,14 @@ public class AdaptivePLLGainMonitor implements ISyncDetectListener, IFrequencyEr * level of the costas loop accordingly. * * @param costasLoop to receive adaptive gain updates. - * @param p25Decoder to receive frequency error source events + * @param p25P1Decoder to receive frequency error source events */ - public AdaptivePLLGainMonitor(CostasLoop costasLoop, P25Decoder p25Decoder) + public AdaptivePLLGainMonitor(CostasLoop costasLoop, P25P1Decoder p25P1Decoder) { mCostasLoop = costasLoop; mCostasLoop.setPLLGain(mPLLGain); mCostasLoop.setFrequencyErrorProcessor(this); - mP25Decoder = p25Decoder; + mP25P1Decoder = p25P1Decoder; } /** @@ -113,7 +117,7 @@ public void processFrequencyError(long frequencyError) //default gain of 1, meaning that we have received at least 2 sync events if(mPLLGain != PLLGain.LEVEL_1) { - mP25Decoder.broadcast(SourceEvent.frequencyErrorMeasurement(frequencyError)); + mP25P1Decoder.broadcast(SourceEvent.frequencyErrorMeasurement(frequencyError)); } } } diff --git a/src/main/java/io/github/dsheirer/dsp/psk/pll/PLLGain.java b/src/main/java/io/github/dsheirer/dsp/psk/pll/PLLGain.java index 2e0a52a6a..f02607b5e 100644 --- a/src/main/java/io/github/dsheirer/dsp/psk/pll/PLLGain.java +++ b/src/main/java/io/github/dsheirer/dsp/psk/pll/PLLGain.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.dsp.psk.pll; /** @@ -22,11 +28,18 @@ public enum PLLGain { //NOTE: static gain level of 200 produced the best results for releases prior to 0.3.4b2 + LEVEL_0(100.0, 0, 0), LEVEL_1(150.0, 0, 1), LEVEL_2(170.0, 2, 4), LEVEL_3(190.0, 5, 6), LEVEL_4(200.0, 7, 8), - LEVEL_5(200.0, 9, 10); + LEVEL_5(200.0, 9, 10), + LEVEL_6(250.0, 11, 12), + LEVEL_7(275.0, 12,13), + LEVEL_8(325.0, 14, 15), + LEVEL_9(350.0, 16,17), + LEVEL_10(375.0, 18, 19), + LEVEL_11(400.0, 19,20); private double mLoopBandwidth; private int mRangeStart; diff --git a/src/main/java/io/github/dsheirer/dsp/symbol/FrameSync.java b/src/main/java/io/github/dsheirer/dsp/symbol/FrameSync.java index d4d82fb99..d1683384f 100644 --- a/src/main/java/io/github/dsheirer/dsp/symbol/FrameSync.java +++ b/src/main/java/io/github/dsheirer/dsp/symbol/FrameSync.java @@ -1,3 +1,25 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + package io.github.dsheirer.dsp.symbol; public enum FrameSync @@ -5,11 +27,13 @@ public enum FrameSync P25_PHASE1_ERROR_90_CCW( 0xFFEFAFAAEEAAl ), P25_PHASE1_NORMAL( 0x5575F5FF77FFl ), // +33333 -3 +33 -33 +33 -3333 +3 -3 +3 -33333 P25_PHASE1_ERROR_90_CW( 0x001050551155l ), - P25_PHASE1_ERROR_180( 0xAA8A0A008800l ); + P25_PHASE1_ERROR_180( 0xAA8A0A008800l ), + + P25_PHASE2_NORMAL(0x575D57F7FFl); private long mSync; - private FrameSync( long sync ) + FrameSync( long sync ) { mSync = sync; } diff --git a/src/main/java/io/github/dsheirer/edac/BerlekempMassey_63.java b/src/main/java/io/github/dsheirer/edac/BerlekempMassey_63.java index 7467d6512..300147c61 100644 --- a/src/main/java/io/github/dsheirer/edac/BerlekempMassey_63.java +++ b/src/main/java/io/github/dsheirer/edac/BerlekempMassey_63.java @@ -1,43 +1,27 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + package io.github.dsheirer.edac; -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014 Dennis Sheirer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - * - * -------------------------------------------------------------------- - * Based on Ed Fuentetaja's DSD RS decoder, May 2014, at: - * https://github.com/szechyjs/dsd/blob/master/ReedSolomon.hpp - * -------------------------------------------------------------------- - * Adapted from Mr. Simon Rockliff's version at: http://www.eccpage.com/rs.c - * - * Simon Rockliff, University of Adelaide 21/9/89 - * 26/6/91 Slight modifications to remove a compiler dependent bug which - * hadn't previously surfaced. A few extra comments added for clarity. - * Appears to all work fine, ready for posting to net! - * - * Notice - * -------- - * This program may be freely modified and/or given to whoever wants it. - * A condition of such distribution is that the author's contribution be - * acknowledged by his name being left in the comments heading the program, - * however no responsibility is accepted for any financial or other loss which - * may result from some unforseen errors or malfunctioning of the program - * during use. - * Simon Rockliff, 26th June 1991 - ******************************************************************************/ import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/github/dsheirer/edac/ReedSolomon_44_16_29.java b/src/main/java/io/github/dsheirer/edac/ReedSolomon_44_16_29.java new file mode 100644 index 000000000..14c4eb016 --- /dev/null +++ b/src/main/java/io/github/dsheirer/edac/ReedSolomon_44_16_29.java @@ -0,0 +1,34 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.edac; + +public class ReedSolomon_44_16_29 extends BerlekempMassey_63 +{ + //Hamming distance = 29, so max correctable errors = 29 / 2 = 14 + private static final int MAXIMUM_CORRECTABLE_ERRORS = 14; + + public ReedSolomon_44_16_29() + { + super(MAXIMUM_CORRECTABLE_ERRORS); + } +} diff --git a/src/main/java/io/github/dsheirer/edac/ReedSolomon_63_35_29.java b/src/main/java/io/github/dsheirer/edac/ReedSolomon_63_35_29.java new file mode 100644 index 000000000..d0155ad86 --- /dev/null +++ b/src/main/java/io/github/dsheirer/edac/ReedSolomon_63_35_29.java @@ -0,0 +1,42 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.edac; + +public class ReedSolomon_63_35_29 extends BerlekempMassey_63 +{ + /** + * Reed-Solomon RS(63,35,29) decoder. This can also be used for error detection and correction of the following + * RS codes: + * + * RS(46,26,21) - max 10 errors = P25P2 IEMI + * RS(45,26,20) - max 9 errors = P25P2 SOEMI (FACCH) + * RS(52,30,23) - max 11 errors = P25P2 IOEMI (SACCH) + * RS(44,16,29) - max 14 errors = P25P2 ESS + * + * The maximum correctable errors is determined by (n-k)/2, or hamming distance divided by 2. + */ + public ReedSolomon_63_35_29(int maximumCorrectableErrors) + { + super(maximumCorrectableErrors); + } +} diff --git a/src/main/java/io/github/dsheirer/gui/SDRTrunk.java b/src/main/java/io/github/dsheirer/gui/SDRTrunk.java index 7bd769e55..2f48dedd4 100644 --- a/src/main/java/io/github/dsheirer/gui/SDRTrunk.java +++ b/src/main/java/io/github/dsheirer/gui/SDRTrunk.java @@ -75,6 +75,8 @@ import javax.swing.JSeparator; import javax.swing.KeyStroke; import javax.swing.UIManager; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; import javax.swing.plaf.metal.MetalLookAndFeel; import java.awt.AWTException; import java.awt.Desktop; @@ -211,7 +213,7 @@ public SDRTrunk() mControllerPanel = new ControllerPanel(audioPlaybackManager, aliasModel, mBroadcastModel, mChannelModel, channelMapModel, mChannelProcessingManager, mIconManager, - mapService, mSettingsManager, mSourceManager, tunerModel, mUserPreferences); + mapService, mSettingsManager, mSourceManager, tunerModel, mUserPreferences, recorderManager); mSpectralPanel = new SpectralDisplayPanel(mChannelModel, mChannelProcessingManager, mSettingsManager, tunerModel); @@ -397,10 +399,11 @@ public void actionPerformed(ActionEvent event) viewMenu.add(new BroadcastStatusVisibleMenuItem(mControllerPanel)); viewMenu.add(new JSeparator()); - for(Tuner tuner : mSourceManager.getTunerModel().getTuners()) - { - viewMenu.add(new ShowTunerMenuItem(mSourceManager.getTunerModel(), tuner)); - } +// for(Tuner tuner : mSourceManager.getTunerModel().getTuners()) +// { +// viewMenu.add(new ShowTunerMenuItem(mSourceManager.getTunerModel(), tuner)); +// } + viewMenu.add(new TunersMenu()); viewMenu.add(new JSeparator()); viewMenu.add(new ClearTunerMenuItem(mSpectralPanel)); @@ -631,6 +634,34 @@ public void actionPerformed(ActionEvent e) } } + public class TunersMenu extends JMenu + { + public TunersMenu() + { + super("Tuners"); + + addMenuListener(new MenuListener() + { + @Override + public void menuSelected(MenuEvent e) + { + removeAll(); + + for(Tuner tuner : mSourceManager.getTunerModel().getTuners()) + { + add(new ShowTunerMenuItem(mSourceManager.getTunerModel(), tuner)); + } + } + + @Override + public void menuDeselected(MenuEvent e) { } + @Override + public void menuCanceled(MenuEvent e) { } + }); + } + + } + /** * Launch the application. */ diff --git a/src/main/java/io/github/dsheirer/gui/instrument/DemodulatorViewerFX.java b/src/main/java/io/github/dsheirer/gui/instrument/DemodulatorViewerFX.java index 06da896dc..eabb518d9 100644 --- a/src/main/java/io/github/dsheirer/gui/instrument/DemodulatorViewerFX.java +++ b/src/main/java/io/github/dsheirer/gui/instrument/DemodulatorViewerFX.java @@ -1,23 +1,29 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.gui.instrument; import io.github.dsheirer.gui.instrument.decoder.DecoderPaneFactory; import io.github.dsheirer.module.decode.DecoderType; -import io.github.dsheirer.module.decode.p25.P25Decoder; +import io.github.dsheirer.module.decode.p25.phase1.P25P1Decoder; import javafx.application.Application; import javafx.application.Platform; import javafx.event.ActionEvent; @@ -61,7 +67,7 @@ public void start(Stage primaryStage) throws Exception borderPane.setTop(getMenuBar()); borderPane.setCenter(getViewerDesktop()); - Scene scene = new Scene(borderPane, 1500, 900); + Scene scene = new Scene(borderPane, 1800, 900); mStage.setScene(scene); mStage.show(); @@ -84,7 +90,7 @@ private void setTitle(DecoderType decoderType) } } - private void setTitle(P25Decoder.Modulation modulation) + private void setTitle(P25P1Decoder.Modulation modulation) { if(modulation != null) { @@ -180,7 +186,7 @@ public void handle(ActionEvent event) @Override public void handle(ActionEvent event) { - getViewerDesktop().setP25Phase1Decoder(P25Decoder.Modulation.C4FM); + getViewerDesktop().setP25Phase1Decoder(P25P1Decoder.Modulation.C4FM); setTitle(decoderType); } }); @@ -194,7 +200,7 @@ public void handle(ActionEvent event) @Override public void handle(ActionEvent event) { - getViewerDesktop().setP25Phase1Decoder(P25Decoder.Modulation.CQPSK); + getViewerDesktop().setP25Phase1Decoder(P25P1Decoder.Modulation.CQPSK); setTitle(decoderType); } }); @@ -203,7 +209,7 @@ public void handle(ActionEvent event) } else { - MenuItem decoderMenuItem = new MenuItem(decoderType.getShortDisplayString()); + MenuItem decoderMenuItem = new MenuItem(decoderType.getDisplayString()); decoderMenuItem.setOnAction(new EventHandler() { diff --git a/src/main/java/io/github/dsheirer/gui/instrument/PlaybackController.java b/src/main/java/io/github/dsheirer/gui/instrument/PlaybackController.java index fd0d31021..ffbbf9cc6 100644 --- a/src/main/java/io/github/dsheirer/gui/instrument/PlaybackController.java +++ b/src/main/java/io/github/dsheirer/gui/instrument/PlaybackController.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.gui.instrument; @@ -205,8 +207,10 @@ private void disableControls() getPlaybackPositionText().setDisable(true); getPlay1Button().setDisable(true); getPlay10Button().setDisable(true); + getPlay30Button().setDisable(true); getPlay100Button().setDisable(true); getPlay1000Button().setDisable(true); + getPlay2000Button().setDisable(true); } /** @@ -218,8 +222,10 @@ private void enableControls() getPlaybackPositionText().setDisable(false); getPlay1Button().setDisable(false); getPlay10Button().setDisable(false); + getPlay30Button().setDisable(false); getPlay100Button().setDisable(false); getPlay1000Button().setDisable(false); + getPlay2000Button().setDisable(false); } private HBox getControlsBox() diff --git a/src/main/java/io/github/dsheirer/gui/instrument/ViewerDesktop.java b/src/main/java/io/github/dsheirer/gui/instrument/ViewerDesktop.java index 293ee6eff..f5e5034b4 100644 --- a/src/main/java/io/github/dsheirer/gui/instrument/ViewerDesktop.java +++ b/src/main/java/io/github/dsheirer/gui/instrument/ViewerDesktop.java @@ -1,24 +1,28 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ package io.github.dsheirer.gui.instrument; import io.github.dsheirer.gui.instrument.decoder.AbstractDecoderPane; import io.github.dsheirer.gui.instrument.decoder.DecoderPaneFactory; import io.github.dsheirer.module.decode.DecoderType; -import io.github.dsheirer.module.decode.p25.P25Decoder; +import io.github.dsheirer.module.decode.p25.phase1.P25P1Decoder; import javafx.scene.layout.BorderPane; import java.io.File; @@ -45,9 +49,9 @@ public void setDecoder(DecoderType decoderType) setDecoderPane(DecoderPaneFactory.getDecoderPane(decoderType)); } - public void setP25Phase1Decoder(P25Decoder.Modulation modulation) + public void setP25Phase1Decoder(P25P1Decoder.Modulation modulation) { - setDecoderPane(DecoderPaneFactory.getP25DecoderPane(modulation)); + setDecoderPane(DecoderPaneFactory.getP25P1DecoderPane(modulation)); } private void setDecoderPane(AbstractDecoderPane decoderPane) diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/ComplexSampleLineChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/ComplexSampleLineChart.java index f567e0a61..55d195660 100644 --- a/src/main/java/io/github/dsheirer/gui/instrument/chart/ComplexSampleLineChart.java +++ b/src/main/java/io/github/dsheirer/gui/instrument/chart/ComplexSampleLineChart.java @@ -1,25 +1,31 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.gui.instrument.chart; import io.github.dsheirer.buffer.ComplexCircularBuffer; -import io.github.dsheirer.dsp.gain.ComplexGain; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.Complex; +import io.github.dsheirer.sample.complex.ComplexSampleListener; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.value.ChangeListener; @@ -32,20 +38,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ComplexSampleLineChart extends LineChart implements Listener +public class ComplexSampleLineChart extends LineChart implements Listener, ComplexSampleListener { private final static Logger mLog = LoggerFactory.getLogger(ComplexSampleLineChart.class); private ComplexCircularBuffer mComplexCircularBuffer; private ComplexCircularBuffer mDemodulationCircularBuffer; - private ComplexGain mComplexGain = new ComplexGain(500.0f); private ObservableList> mISamples = FXCollections.observableArrayList(); private ObservableList> mQSamples = FXCollections.observableArrayList(); private IntegerProperty mLengthProperty = new SimpleIntegerProperty(40); - public ComplexSampleLineChart(int length, int samplesPerSymbol) + public ComplexSampleLineChart(String label, int length, int samplesPerSymbol) { - super(new NumberAxis("Differential-Demodulated Samples", 0, length, 10), + super(new NumberAxis(label, 0, length, 10), new NumberAxis("Value", -1.0, 1.0, 0.25)); LineChart.Series iSampleSeries = new LineChart.Series<>("Inphase", mISamples); @@ -96,24 +101,25 @@ public void receive(ReusableComplexBuffer complexBuffer) { float[] samples = complexBuffer.getSamples(); - Complex sample = new Complex(0,0); - for(int x = 0; x < samples.length; x += 2) { - sample.setValues(samples[x], samples[x + 1]); -// mComplexGain.apply(sample); - sample.normalize(); - - Complex previous = mDemodulationCircularBuffer.get(sample.copy()); - sample.multiply(previous.conjugate()); - mComplexCircularBuffer.put(sample.copy()); + receive(samples[x], samples[x + 1]); } - updateChart(); - complexBuffer.decrementUserCount(); } + @Override + public void receive(float i, float q) + { + Complex sample = new Complex(i,q); + sample.normalize(); + Complex previous = mDemodulationCircularBuffer.get(sample.copy()); + sample.multiply(previous.conjugate()); + mComplexCircularBuffer.put(sample); + updateChart(); + } + private void updateChart() { Complex[] samples = mComplexCircularBuffer.getAll(); diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/EyeDiagramChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/EyeDiagramChart.java index a00db2784..cede2e585 100644 --- a/src/main/java/io/github/dsheirer/gui/instrument/chart/EyeDiagramChart.java +++ b/src/main/java/io/github/dsheirer/gui/instrument/chart/EyeDiagramChart.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.gui.instrument.chart; import io.github.dsheirer.dsp.psk.SymbolDecisionData; @@ -29,17 +35,17 @@ public class EyeDiagramChart extends LineChart implements Listener> mData = FXCollections.observableArrayList(); + private ObservableList> mData = FXCollections.observableArrayList(); private int mSeriesCount; private int mSeriesPointer; private int mSeriesLength; public EyeDiagramChart(int seriesCount, String legend) { - super(new NumberAxis("Symbol Timing (" + legend + ")", 1.0, 10.0, 1.0), - new NumberAxis("Value", -1.25, 1.25, 0.25)); + super(new NumberAxis("Sample Point = 3", -1.0, 7.0, 1.0), + new NumberAxis("Radians", -5.0, 5.0, 0.5)); - mSeriesCount = seriesCount * 2; + mSeriesCount = seriesCount; init(); } @@ -48,15 +54,15 @@ private void init() for(int x = 0; x < mSeriesCount; x++) { ObservableList> series = FXCollections.observableArrayList(); - mData.add(new Series<>(series)); + mData.add(new Series(series)); } setData(mData); } - private ObservableList> getSeries(int series, int length) + private ObservableList> getSeries(int series, int length) { - ObservableList> seriesData = mData.get(series).getData(); + ObservableList> seriesData = mData.get(series).getData(); while(seriesData.size() > length) { @@ -65,7 +71,7 @@ private ObservableList> getSeries(int series, int length) while(seriesData.size() < length) { - seriesData.add(new Data(0.0,0.0)); + seriesData.add(new Data<>(0.0,0.0f)); } return seriesData; @@ -80,42 +86,63 @@ private void checkChartLength(int length) } } - @Override - public void receive(SymbolDecisionData symbolDecisionData) + private float[] conditionData(Complex[] samples) { - Complex[] demodulated = symbolDecisionData.getDemodulated(); - - int length = demodulated.length; + Float previousAngle = null; + float[] corrected = new float[samples.length]; - checkChartLength(length); + int phaseRolloverIndex = -1; + for(int x = 0; x < samples.length; x++) + { + corrected[x] = samples[x].angle(); - ObservableList> iSeries = getSeries(mSeriesPointer++, length + 1); + if(x > 0 && (Math.abs(corrected[x] - corrected[x - 1]) > Math.PI)) + { + phaseRolloverIndex = x; + } + } - if(mSeriesPointer >= mSeriesCount) + if(phaseRolloverIndex >= 0) { - mSeriesPointer = 0; + for(int x = 0; x < phaseRolloverIndex; x++) + { + if(corrected[x] > 0) + { + corrected[x] -= 2 * Math.PI; + } + else + { + corrected[x] += 2 * Math.PI; + } + } } - ObservableList> qSeries = getSeries(mSeriesPointer++, length + 1); + return corrected; + } + + @Override + public void receive(SymbolDecisionData symbolDecisionData) + { + Complex[] samples = symbolDecisionData.getSamples(); + int length = samples.length; + + ObservableList> iSeries = getSeries(mSeriesPointer++, length); +// checkChartLength(length); if(mSeriesPointer >= mSeriesCount) { mSeriesPointer = 0; } - for(int x = 0; x < length; x++) + float[] angles = conditionData(samples); + + for(int x = 0; x < samples.length; x++) { - demodulated[x].normalize(); - Data iDataPoint = iSeries.get(x); - iDataPoint.setXValue((double)x + 1 - symbolDecisionData.getSamplingPoint()); - double iValue = demodulated[x].inphase(); - iDataPoint.setYValue(iValue); - - Data qDataPoint = qSeries.get(x); - qDataPoint.setXValue((double)x + 1 - symbolDecisionData.getSamplingPoint()); - double qValue = demodulated[x].quadrature(); - qDataPoint.setYValue(qValue); + Data iDataPoint = iSeries.get(x); + Complex sample = samples[x]; + iDataPoint.setXValue((double)x - symbolDecisionData.getSamplingPoint()); + iDataPoint.setYValue(angles[x]); } } } diff --git a/src/main/java/io/github/dsheirer/gui/instrument/chart/SampleXYChart.java b/src/main/java/io/github/dsheirer/gui/instrument/chart/SampleXYChart.java new file mode 100644 index 000000000..1dc19166c --- /dev/null +++ b/src/main/java/io/github/dsheirer/gui/instrument/chart/SampleXYChart.java @@ -0,0 +1,96 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.gui.instrument.chart; + +import eu.hansolo.fx.charts.ChartType; +import eu.hansolo.fx.charts.PolarChart; +import eu.hansolo.fx.charts.XYPane; +import eu.hansolo.fx.charts.data.XYChartItem; +import eu.hansolo.fx.charts.series.XYSeries; +import io.github.dsheirer.buffer.ComplexCircularBuffer; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.sample.complex.Complex; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.scene.paint.Color; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SampleXYChart extends PolarChart implements Listener +{ + private static ObservableList sChartItemList = FXCollections.observableArrayList(); + + static + { + sChartItemList.add(new XYChartItem(1, 1)); + sChartItemList.add(new XYChartItem(-1, -1)); + } + + private final static Logger mLog = LoggerFactory.getLogger(SampleXYChart.class); + private ComplexCircularBuffer mCircularBuffer; + private int mSampleCount; + + public SampleXYChart(int sampleCount, String title) + { + super(new XYPane<>(new XYSeries<>(sChartItemList, ChartType.POLAR))); + mSampleCount = sampleCount; + mCircularBuffer = new ComplexCircularBuffer(mSampleCount); + + getXYPane().setLowerBoundX(0); + getXYPane().setUpperBoundX(1.0); + getXYPane().setLowerBoundY(0); + getXYPane().setUpperBoundY(1.0); + } + + private void init() + { + } + + @Override + public void receive(ReusableComplexBuffer buffer) + { + float[] samples = buffer.getSamples(); + + for(int x = 0; x < samples.length; x += 2) + { + mCircularBuffer.put(new Complex(samples[x], samples[x + 1])); + } + + buffer.decrementUserCount(); + + Complex[] complexSamples = mCircularBuffer.getAll(); + + XYSeries series = getXYPane().getListOfSeries().get(0); + series.setStroke(Color.BLUE); + + series.getItems().clear(); + + for(int x = 0; x < complexSamples.length; x++) + { + Complex sample = complexSamples[x]; + series.getItems().add(new XYChartItem(sample.polarAngleDegrees(), sample.magnitude(), Color.BLUE)); + } + + refresh(); + } +} diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/DecoderPaneFactory.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/DecoderPaneFactory.java index 3b2c8ff0e..5702f4dad 100644 --- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/DecoderPaneFactory.java +++ b/src/main/java/io/github/dsheirer/gui/instrument/decoder/DecoderPaneFactory.java @@ -1,22 +1,26 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ package io.github.dsheirer.gui.instrument.decoder; import io.github.dsheirer.module.decode.DecoderType; -import io.github.dsheirer.module.decode.p25.P25Decoder; +import io.github.dsheirer.module.decode.p25.phase1.P25P1Decoder; import java.util.EnumSet; @@ -24,6 +28,7 @@ public class DecoderPaneFactory { private static final EnumSet SUPPORTED_DECODER_TYPES = EnumSet.of( DecoderType.P25_PHASE1, + DecoderType.P25_PHASE2, DecoderType.FLEETSYNC2, DecoderType.LJ_1200, DecoderType.LTR_NET, @@ -51,7 +56,9 @@ public static AbstractDecoderPane getDecoderPane(DecoderType decoderType) case TAIT_1200: return new Tait1200Pane(); case P25_PHASE1: - throw new IllegalArgumentException("Use the getP25DecoderPane() method for P25 decoder type"); + throw new IllegalArgumentException("Use the getP25P1DecoderPane() method for P25 decoder type"); + case P25_PHASE2: + return new P25Phase2HDQPSKPane(); } return getDefaultPane(); @@ -60,7 +67,7 @@ public static AbstractDecoderPane getDecoderPane(DecoderType decoderType) /** * Creates a decoder pane for the P25 decoder type */ - public static AbstractDecoderPane getP25DecoderPane(P25Decoder.Modulation modulation) + public static AbstractDecoderPane getP25P1DecoderPane(P25P1Decoder.Modulation modulation) { switch(modulation) { diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1C4FMPane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1C4FMPane.java index d691c853a..853d7dbdb 100644 --- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1C4FMPane.java +++ b/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1C4FMPane.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.gui.instrument.decoder; import io.github.dsheirer.gui.instrument.chart.ComplexSampleLineChart; @@ -22,7 +28,7 @@ import io.github.dsheirer.gui.instrument.chart.SymbolChart; import io.github.dsheirer.message.IMessage; import io.github.dsheirer.module.decode.DecoderType; -import io.github.dsheirer.module.decode.p25.P25DecoderC4FMInstrumented; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderC4FMInstrumented; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster; import javafx.scene.layout.HBox; @@ -43,7 +49,7 @@ public class P25Phase1C4FMPane extends ComplexDecoderPane private DoubleLineChart mPLLFrequencyLineChart; private DoubleLineChart mSamplesPerSymbolLineChart; private ReusableBufferBroadcaster mFilteredBufferBroadcaster = new ReusableBufferBroadcaster(); - private P25DecoderC4FMInstrumented mDecoder = new P25DecoderC4FMInstrumented(); + private P25P1DecoderC4FMInstrumented mDecoder = new P25P1DecoderC4FMInstrumented(); public P25Phase1C4FMPane() { @@ -89,7 +95,7 @@ public void setSampleRate(double sampleRate) getSampleLineChart().setSamplesPerSymbol((int) samplesPerSymbol); } - private P25DecoderC4FMInstrumented getDecoder() + private P25P1DecoderC4FMInstrumented getDecoder() { return mDecoder; } @@ -146,7 +152,7 @@ private ComplexSampleLineChart getSampleLineChart() { if(mSampleLineChart == null) { - mSampleLineChart = new ComplexSampleLineChart(100, 10); + mSampleLineChart = new ComplexSampleLineChart("Raw Samples", 100, 10); } return mSampleLineChart; diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1LSMPane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1LSMPane.java index 3272889f5..56c875889 100644 --- a/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1LSMPane.java +++ b/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase1LSMPane.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.gui.instrument.decoder; import io.github.dsheirer.gui.instrument.chart.ComplexSampleLineChart; @@ -23,7 +29,7 @@ import io.github.dsheirer.gui.instrument.chart.SymbolChart; import io.github.dsheirer.message.IMessage; import io.github.dsheirer.module.decode.DecoderType; -import io.github.dsheirer.module.decode.p25.P25DecoderLSMInstrumented; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderLSMInstrumented; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster; import javafx.scene.layout.HBox; @@ -44,7 +50,7 @@ public class P25Phase1LSMPane extends ComplexDecoderPane private DoubleLineChart mPLLFrequencyLineChart; private SamplesPerSymbolChart mSamplesPerSymbolLineChart; private ReusableBufferBroadcaster mFilteredBufferBroadcaster = new ReusableBufferBroadcaster(); - private P25DecoderLSMInstrumented mDecoder = new P25DecoderLSMInstrumented(); + private P25P1DecoderLSMInstrumented mDecoder = new P25P1DecoderLSMInstrumented(); public P25Phase1LSMPane() { @@ -91,7 +97,7 @@ public void setSampleRate(double sampleRate) getSamplesPerSymbolLineChart().setSamplesPerSymbol(samplesPerSymbol); } - private P25DecoderLSMInstrumented getDecoder() + private P25P1DecoderLSMInstrumented getDecoder() { return mDecoder; } @@ -148,7 +154,7 @@ private ComplexSampleLineChart getDifferentialDemodulatedSamplesChartBox() { if(mDifferentialDemodulatedSamplesChartBox == null) { - mDifferentialDemodulatedSamplesChartBox = new ComplexSampleLineChart(100, 10); + mDifferentialDemodulatedSamplesChartBox = new ComplexSampleLineChart("Raw Samples", 100, 10); } return mDifferentialDemodulatedSamplesChartBox; diff --git a/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase2HDQPSKPane.java b/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase2HDQPSKPane.java new file mode 100644 index 000000000..833fed724 --- /dev/null +++ b/src/main/java/io/github/dsheirer/gui/instrument/decoder/P25Phase2HDQPSKPane.java @@ -0,0 +1,242 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.gui.instrument.decoder; + +import io.github.dsheirer.gui.instrument.chart.ComplexSampleLineChart; +import io.github.dsheirer.gui.instrument.chart.DoubleLineChart; +import io.github.dsheirer.gui.instrument.chart.EyeDiagramChart; +import io.github.dsheirer.gui.instrument.chart.PhaseLineChart; +import io.github.dsheirer.gui.instrument.chart.SampleXYChart; +import io.github.dsheirer.gui.instrument.chart.SymbolChart; +import io.github.dsheirer.message.IMessage; +import io.github.dsheirer.module.decode.DecoderType; +import io.github.dsheirer.module.decode.p25.phase2.DecodeConfigP25Phase2; +import io.github.dsheirer.module.decode.p25.phase2.P25P2DecoderHDQPSKInstrumented; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class P25Phase2HDQPSKPane extends ComplexDecoderPane +{ + private final static Logger mLog = LoggerFactory.getLogger(P25Phase2HDQPSKPane.class); + + private HBox mSampleChartBox; + private HBox mDecoderChartBox; + + private ComplexSampleLineChart mSampleLineChartRaw; + private ComplexSampleLineChart mSampleLineChartPllCorrected; + private EyeDiagramChart mEyeDiagramChart; + private DoubleLineChart mSamplesPerSymbolLineChart; + + private SymbolChart mSymbolChart; + private PhaseLineChart mPLLPhaseErrorLineChart; + private DoubleLineChart mPLLFrequencyLineChart; + private SampleXYChart mSampleXYChart; + + + private ReusableBufferBroadcaster mFilteredBufferBroadcaster = new ReusableBufferBroadcaster(); + private P25P2DecoderHDQPSKInstrumented mDecoder = new P25P2DecoderHDQPSKInstrumented(new DecodeConfigP25Phase2()); + + public P25Phase2HDQPSKPane() + { + super(DecoderType.P25_PHASE2); + init(); + } + + private void init() + { + addListener(getDecoder()); + + getDecoder().getDemodulator().setFilteredGainAppliedComplexBufferListener(getSampleXYChart()); + + getDecoder().setFilteredBufferListener(mFilteredBufferBroadcaster); + getDecoder().setComplexSymbolListener(getSymbolChart()); + getDecoder().setPLLPhaseErrorListener(getPLLPhaseErrorLineChart()); + getDecoder().setPLLFrequencyListener(getPLLFrequencyLineChart()); + getDecoder().setSymbolDecisionDataListener(getEyeDiagramChart()); + getDecoder().setSamplesPerSymbolListener(getSamplesPerSymbolLineChart()); + + //Listen for raw (uncorrected) samples + mFilteredBufferBroadcaster.addListener(getSampleLineChartRaw()); + + //Listen for PLL corrected samples + getDecoder().getSampleBuffer().setSampleListener(getSampleLineChartPllCorrected()); + + HBox.setHgrow(getSampleChartBox(), Priority.ALWAYS); + HBox.setHgrow(getDecoderChartBox(), Priority.ALWAYS); + getChildren().addAll(getSampleChartBox(), getDecoderChartBox()); + + mDecoder.setMessageListener(new Listener() + { + @Override + public void receive(IMessage message) + { + mLog.debug(message.toString()); + } + }); + + } + + @Override + public void setSampleRate(double sampleRate) + { + mLog.debug("Configuring for sample rate: " + sampleRate); + + mDecoder.setSampleRate(sampleRate); + double samplesPerSymbol = sampleRate / 4800.0; + + getSampleLineChartRaw().setSamplesPerSymbol((int) samplesPerSymbol); + getDecoder().getSampleBuffer().setSampleListener(getSampleLineChartPllCorrected()); + getDecoder().getDemodulator().setFilteredGainAppliedComplexBufferListener(getSampleXYChart()); + } + + private P25P2DecoderHDQPSKInstrumented getDecoder() + { + return mDecoder; + } + + private SymbolChart getSymbolChart() + { + if(mSymbolChart == null) + { + mSymbolChart = new SymbolChart(10); + } + + return mSymbolChart; + } + + private HBox getDecoderChartBox() + { + if(mDecoderChartBox == null) + { + mDecoderChartBox = new HBox(); + mDecoderChartBox.setMaxHeight(Double.MAX_VALUE); + getSymbolChart().setMaxWidth(Double.MAX_VALUE); + getPLLPhaseErrorLineChart().setMaxWidth(Double.MAX_VALUE); + getPLLFrequencyLineChart().setMaxWidth(Double.MAX_VALUE); + getSampleXYChart().setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(getSymbolChart(), Priority.ALWAYS); + HBox.setHgrow(getPLLPhaseErrorLineChart(), Priority.ALWAYS); + HBox.setHgrow(getPLLFrequencyLineChart(), Priority.ALWAYS); + HBox.setHgrow(getSampleXYChart(), Priority.ALWAYS); + mDecoderChartBox.getChildren().addAll(getPLLPhaseErrorLineChart(), getPLLFrequencyLineChart(), + getSymbolChart(), getSampleXYChart()); + } + + return mDecoderChartBox; + } + + private HBox getSampleChartBox() + { + if(mSampleChartBox == null) + { + mSampleChartBox = new HBox(); + mSampleChartBox.setMaxHeight(Double.MAX_VALUE); + getSampleLineChartRaw().setMaxWidth(Double.MAX_VALUE); + getSampleLineChartPllCorrected().setMaxWidth(Double.MAX_VALUE); + getEyeDiagramChart().setMaxWidth(Double.MAX_VALUE); + getSamplesPerSymbolLineChart().setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(getSampleLineChartRaw(), Priority.ALWAYS); + HBox.setHgrow(getSampleLineChartPllCorrected(), Priority.ALWAYS); + HBox.setHgrow(getEyeDiagramChart(), Priority.ALWAYS); + HBox.setHgrow(getSamplesPerSymbolLineChart(), Priority.ALWAYS); + + mSampleChartBox.getChildren().addAll(getSampleLineChartRaw(), getSampleLineChartPllCorrected(), + getEyeDiagramChart(), getSamplesPerSymbolLineChart()); + } + + return mSampleChartBox; + } + + private ComplexSampleLineChart getSampleLineChartRaw() + { + if(mSampleLineChartRaw == null) + { + mSampleLineChartRaw = new ComplexSampleLineChart("Raw Samples", 100, 10); + } + + return mSampleLineChartRaw; + } + + private ComplexSampleLineChart getSampleLineChartPllCorrected() + { + if(mSampleLineChartPllCorrected == null) + { + mSampleLineChartPllCorrected = new ComplexSampleLineChart("PLL Corrected Samples", 100, 10); + } + + return mSampleLineChartPllCorrected; + } + + private EyeDiagramChart getEyeDiagramChart() + { + if(mEyeDiagramChart == null) + { + mEyeDiagramChart = new EyeDiagramChart(10, "Symbol: 3-4"); + } + + return mEyeDiagramChart; + } + + private PhaseLineChart getPLLPhaseErrorLineChart() + { + if(mPLLPhaseErrorLineChart == null) + { + mPLLPhaseErrorLineChart = new PhaseLineChart(40); + } + + return mPLLPhaseErrorLineChart; + } + + private DoubleLineChart getPLLFrequencyLineChart() + { + if(mPLLFrequencyLineChart == null) + { + mPLLFrequencyLineChart = new DoubleLineChart("PLL Frequency", -500, 500, 50, 40); + } + + return mPLLFrequencyLineChart; + } + + private SampleXYChart getSampleXYChart() + { + if(mSampleXYChart == null) + { + mSampleXYChart = new SampleXYChart(100, "Samples"); + } + + return mSampleXYChart; + } + + private DoubleLineChart getSamplesPerSymbolLineChart() + { + if(mSamplesPerSymbolLineChart == null) + { + mSamplesPerSymbolLineChart = new DoubleLineChart("Sample Point", 8.0, 10.0, 0.1, 40); + } + + return mSamplesPerSymbolLineChart; + } +} diff --git a/src/main/java/io/github/dsheirer/identifier/Form.java b/src/main/java/io/github/dsheirer/identifier/Form.java index 09f7ddf64..4132aa5e5 100644 --- a/src/main/java/io/github/dsheirer/identifier/Form.java +++ b/src/main/java/io/github/dsheirer/identifier/Form.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.identifier; @@ -25,26 +27,32 @@ public enum Form { ALIAS_LIST, + CALL_PROGRESS_TONE, CHANNEL, CHANNEL_DESCRIPTOR, CHANNEL_NAME, CHANNEL_FREQUENCY, DECODER_TYPE, + DTMF, ENCRYPTION_KEY, ESN, + FULLY_QUALIFIED_IDENTIFIER, IPV4_ADDRESS, + KNOX_TONE, LOCATION_REGISTRATION_AREA, LOJACK, NEIGHBOR_SITE, NETWORK_ACCESS_CODE, PATCH_GROUP, RF_SUBSYSTEM, + SCRAMBLE_PARAMETERS, SHORT_DATA_MESSAGE, SITE, STATE, SYSTEM, TALKGROUP, TELEPHONE_NUMBER, + TONE, UNIT_IDENTIFIER, UNIT_STATUS, USER_STATUS, diff --git a/src/main/java/io/github/dsheirer/identifier/IdentifierCollection.java b/src/main/java/io/github/dsheirer/identifier/IdentifierCollection.java index 1a3bf75d0..82ae27108 100644 --- a/src/main/java/io/github/dsheirer/identifier/IdentifierCollection.java +++ b/src/main/java/io/github/dsheirer/identifier/IdentifierCollection.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.identifier; @@ -40,15 +42,31 @@ public class IdentifierCollection protected List mIdentifiers = new ArrayList<>(); protected AliasListConfigurationIdentifier mAliasListConfigurationIdentifier; private boolean mUpdated = false; + private int mTimeslot = 0; + + /** + * Constructs an empty identifier collection for the specified timeslot + * @param timeslot + */ + public IdentifierCollection(int timeslot) + { + mTimeslot = timeslot; + } /** * Constructs an empty identifier collection */ public IdentifierCollection() { + this(0); } public IdentifierCollection(Collection identifiers) + { + this(identifiers, 0); + } + + public IdentifierCollection(Collection identifiers, int timeslot) { for(Identifier identifier: identifiers) { @@ -66,14 +84,14 @@ public IdentifierCollection(Collection identifiers) } } - public IdentifierCollection(Identifier identifier) + public int getTimeslot() { - if(identifier == null) - { - throw new IllegalArgumentException("Identifier cannot be null"); - } + return mTimeslot; + } - mIdentifiers.add(identifier); + public void setTimeslot(int timeslot) + { + mTimeslot = timeslot; } /** diff --git a/src/main/java/io/github/dsheirer/identifier/IdentifierUpdateNotification.java b/src/main/java/io/github/dsheirer/identifier/IdentifierUpdateNotification.java index 6b18222e3..83c5415fb 100644 --- a/src/main/java/io/github/dsheirer/identifier/IdentifierUpdateNotification.java +++ b/src/main/java/io/github/dsheirer/identifier/IdentifierUpdateNotification.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.identifier; @@ -27,15 +29,17 @@ public class IdentifierUpdateNotification { private Identifier mIdentifier; private Operation mOperation; + private int mTimeslot; /** * Constructs an identifier update notification * @param identifier that has been updated */ - public IdentifierUpdateNotification(Identifier identifier, Operation operation) + public IdentifierUpdateNotification(Identifier identifier, Operation operation, int timeslot) { mIdentifier = identifier; mOperation = operation; + mTimeslot = timeslot; } public Identifier getIdentifier() @@ -48,6 +52,11 @@ public Operation getOperation() return mOperation; } + public int getTimeslot() + { + return mTimeslot; + } + public boolean isAdd() { return mOperation == Operation.ADD; diff --git a/src/main/java/io/github/dsheirer/identifier/MutableIdentifierCollection.java b/src/main/java/io/github/dsheirer/identifier/MutableIdentifierCollection.java index 92aee888a..04e1ab700 100644 --- a/src/main/java/io/github/dsheirer/identifier/MutableIdentifierCollection.java +++ b/src/main/java/io/github/dsheirer/identifier/MutableIdentifierCollection.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.identifier; @@ -37,12 +39,25 @@ public class MutableIdentifierCollection extends IdentifierCollection implements private final static Logger mLog = LoggerFactory.getLogger(MutableIdentifierCollection.class); private Listener mListener; + public MutableIdentifierCollection(int timeslot) + { + super(timeslot); + } + public MutableIdentifierCollection() { + super(0); } public MutableIdentifierCollection(Collection identifiers) { + this(identifiers, 0); + } + + public MutableIdentifierCollection(Collection identifiers, int timeslot) + { + super(timeslot); + for(Identifier identifier: identifiers) { update(identifier); @@ -86,7 +101,7 @@ private void notifyAdd(Identifier identifier) setUpdated(true); if(mListener != null) { - mListener.receive(new IdentifierUpdateNotification(identifier, IdentifierUpdateNotification.Operation.ADD)); + mListener.receive(new IdentifierUpdateNotification(identifier, IdentifierUpdateNotification.Operation.ADD, getTimeslot())); } } @@ -99,7 +114,7 @@ private void notifyRemove(Identifier identifier) if(mListener != null) { mListener.receive(new IdentifierUpdateNotification(identifier, - IdentifierUpdateNotification.Operation.REMOVE)); + IdentifierUpdateNotification.Operation.REMOVE, getTimeslot())); } } @@ -365,26 +380,25 @@ public void remove(IdentifierClass identifierClass, Role role) * Implements the listener interface to receive notifications of identifier updates. This allows an * identifier collection to maintain a synchronized state with a remote identifier collection. * + * Note: this method performs a silent add/update/remove on on the local collection and does not rebroadcast + * the update to a registered listener in order to prevent infinite loop updates. + * * @param identifierUpdateNotification to add or remove an identifier */ @Override public void receive(IdentifierUpdateNotification identifierUpdateNotification) { - if(identifierUpdateNotification.isAdd()) - { - update(identifierUpdateNotification.getIdentifier()); - } - else if(identifierUpdateNotification.isRemove()) - { - remove(identifierUpdateNotification.getIdentifier()); - } - else if(identifierUpdateNotification.isSilentAdd()) - { - silentUpdate(identifierUpdateNotification.getIdentifier()); - } - else if(identifierUpdateNotification.isSilentRemove()) + //Only process notifications that match this timeslot + if(identifierUpdateNotification.getTimeslot() == getTimeslot()) { - silentRemove(identifierUpdateNotification.getIdentifier()); + if(identifierUpdateNotification.isAdd() || identifierUpdateNotification.isSilentAdd()) + { + silentUpdate(identifierUpdateNotification.getIdentifier()); + } + else if(identifierUpdateNotification.isRemove() || identifierUpdateNotification.isSilentRemove()) + { + silentRemove(identifierUpdateNotification.getIdentifier()); + } } } @@ -394,7 +408,7 @@ else if(identifierUpdateNotification.isSilentRemove()) */ public IdentifierCollection copyOf() { - IdentifierCollection copy = new IdentifierCollection(getIdentifiers()); + IdentifierCollection copy = new IdentifierCollection(getIdentifiers(), getTimeslot()); copy.setUpdated(isUpdated()); setUpdated(false); return copy; diff --git a/src/main/java/io/github/dsheirer/identifier/encryption/EncryptionKey.java b/src/main/java/io/github/dsheirer/identifier/encryption/EncryptionKey.java index 67f8e152a..c6d8dbece 100644 --- a/src/main/java/io/github/dsheirer/identifier/encryption/EncryptionKey.java +++ b/src/main/java/io/github/dsheirer/identifier/encryption/EncryptionKey.java @@ -1,28 +1,30 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.identifier.encryption; import java.util.Objects; -public class EncryptionKey implements Comparable +public abstract class EncryptionKey implements Comparable { private int mAlgorithm; private int mKey; @@ -33,10 +35,7 @@ public EncryptionKey(int algorithm, int key) mKey = key; } - public boolean isEncrypted() - { - return mAlgorithm != 0x80; - } + public abstract boolean isEncrypted(); public int getAlgorithm() { diff --git a/src/main/java/io/github/dsheirer/identifier/encryption/EncryptionKeyIdentifier.java b/src/main/java/io/github/dsheirer/identifier/encryption/EncryptionKeyIdentifier.java index 51176a2e2..f14affd81 100644 --- a/src/main/java/io/github/dsheirer/identifier/encryption/EncryptionKeyIdentifier.java +++ b/src/main/java/io/github/dsheirer/identifier/encryption/EncryptionKeyIdentifier.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.identifier.encryption; @@ -24,13 +26,28 @@ import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.identifier.IdentifierClass; import io.github.dsheirer.identifier.Role; +import io.github.dsheirer.protocol.Protocol; -public abstract class EncryptionKeyIdentifier extends Identifier +public class EncryptionKeyIdentifier extends Identifier { public EncryptionKeyIdentifier(EncryptionKey value, IdentifierClass identifierClass, Form form, Role role) { super(value, identifierClass, form, role); } + @Override + public Protocol getProtocol() + { + return Protocol.APCO25; + } + public boolean isEncrypted() + { + return getValue() != null && getValue().isEncrypted(); + } + + public static EncryptionKeyIdentifier create(EncryptionKey encryptionKey) + { + return new EncryptionKeyIdentifier(encryptionKey, IdentifierClass.USER, Form.ENCRYPTION_KEY, Role.ANY); + } } diff --git a/src/main/java/io/github/dsheirer/identifier/scramble/ScrambleParameterIdentifier.java b/src/main/java/io/github/dsheirer/identifier/scramble/ScrambleParameterIdentifier.java new file mode 100644 index 000000000..ce2de1bd4 --- /dev/null +++ b/src/main/java/io/github/dsheirer/identifier/scramble/ScrambleParameterIdentifier.java @@ -0,0 +1,64 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.identifier.scramble; + +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.module.decode.p25.phase2.enumeration.ScrambleParameters; +import io.github.dsheirer.protocol.Protocol; + +/** + * APCO25 Phase II Scramble Parameters Identifier + */ +public class ScrambleParameterIdentifier extends Identifier +{ + /** + * Constructs an instance + * @param value to wrap in this instance + */ + private ScrambleParameterIdentifier(ScrambleParameters value) + { + super(value, IdentifierClass.NETWORK, Form.SCRAMBLE_PARAMETERS, Role.BROADCAST); + } + + /** + * P25P2 Protocol + */ + @Override + public Protocol getProtocol() + { + return Protocol.APCO25_PHASE2; + } + + /** + * Creates an instance + * @param scrambleParameters to wrap in an identifier + */ + public static ScrambleParameterIdentifier create(ScrambleParameters scrambleParameters) + { + return new ScrambleParameterIdentifier(scrambleParameters); + } +} + diff --git a/src/main/java/io/github/dsheirer/identifier/string/StringListIdentifier.java b/src/main/java/io/github/dsheirer/identifier/string/StringListIdentifier.java new file mode 100644 index 000000000..66ae4dc05 --- /dev/null +++ b/src/main/java/io/github/dsheirer/identifier/string/StringListIdentifier.java @@ -0,0 +1,41 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.identifier.string; + +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 java.util.List; + +/** + * String identifier base class + */ +public abstract class StringListIdentifier extends Identifier> +{ + public StringListIdentifier(List values, IdentifierClass identifierClass, Form form, Role role) + { + super(values, identifierClass, form, role); + } +} diff --git a/src/main/java/io/github/dsheirer/identifier/talkgroup/FullyQualifiedIdentifier.java b/src/main/java/io/github/dsheirer/identifier/talkgroup/FullyQualifiedIdentifier.java new file mode 100644 index 000000000..8f31cfe1b --- /dev/null +++ b/src/main/java/io/github/dsheirer/identifier/talkgroup/FullyQualifiedIdentifier.java @@ -0,0 +1,64 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.identifier.talkgroup; + +/** + * Fully qualified radio identifier + */ +public class FullyQualifiedIdentifier +{ + private int mWacn; + private int mSystem; + private int mId; + + /** + * Constructs an instance + * @param wacn + * @param system + * @param id + */ + public FullyQualifiedIdentifier(int wacn, int system, int id) + { + mWacn = wacn; + mSystem = system; + mId = id; + } + + @Override + public String toString() + { + return mWacn + "." + mSystem + "." + mId; + } + + /** + * Creates an instance with the specified values + * @param wacn value + * @param system value + * @param id value + * @return instance + */ + public static FullyQualifiedIdentifier create(int wacn, int system, int id) + { + return new FullyQualifiedIdentifier(wacn, system, id); + } +} diff --git a/src/main/java/io/github/dsheirer/identifier/tone/CallProgressIdentifier.java b/src/main/java/io/github/dsheirer/identifier/tone/CallProgressIdentifier.java new file mode 100644 index 000000000..80763c8a5 --- /dev/null +++ b/src/main/java/io/github/dsheirer/identifier/tone/CallProgressIdentifier.java @@ -0,0 +1,48 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.identifier.tone; + +import com.google.common.base.Joiner; +import io.github.dsheirer.identifier.Form; +import io.github.dsheirer.identifier.IdentifierClass; +import io.github.dsheirer.identifier.Role; +import io.github.dsheirer.identifier.string.StringListIdentifier; + +import java.util.List; + +/** + * Call Progress (ie dial tone, busy tone) tones identifier + */ +public abstract class CallProgressIdentifier extends StringListIdentifier +{ + public CallProgressIdentifier(List values) + { + super(values, IdentifierClass.USER, Form.CALL_PROGRESS_TONE, Role.TO); + } + + @Override + public String toString() + { + return "CALL:" + Joiner.on("").join(getValue()); + } +} diff --git a/src/main/java/io/github/dsheirer/identifier/tone/DtmfIdentifier.java b/src/main/java/io/github/dsheirer/identifier/tone/DtmfIdentifier.java new file mode 100644 index 000000000..d54396c30 --- /dev/null +++ b/src/main/java/io/github/dsheirer/identifier/tone/DtmfIdentifier.java @@ -0,0 +1,48 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.identifier.tone; + +import com.google.common.base.Joiner; +import io.github.dsheirer.identifier.Form; +import io.github.dsheirer.identifier.IdentifierClass; +import io.github.dsheirer.identifier.Role; +import io.github.dsheirer.identifier.string.StringListIdentifier; + +import java.util.List; + +/** + * Dual-Tone Multi-Frequency (DTMF) tones identifier + */ +public abstract class DtmfIdentifier extends StringListIdentifier +{ + public DtmfIdentifier(List values) + { + super(values, IdentifierClass.USER, Form.DTMF, Role.TO); + } + + @Override + public String toString() + { + return "DTMF:" + Joiner.on("").join(getValue()); + } +} diff --git a/src/main/java/io/github/dsheirer/identifier/tone/KnoxIdentifier.java b/src/main/java/io/github/dsheirer/identifier/tone/KnoxIdentifier.java new file mode 100644 index 000000000..c7de91f74 --- /dev/null +++ b/src/main/java/io/github/dsheirer/identifier/tone/KnoxIdentifier.java @@ -0,0 +1,48 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.identifier.tone; + +import com.google.common.base.Joiner; +import io.github.dsheirer.identifier.Form; +import io.github.dsheirer.identifier.IdentifierClass; +import io.github.dsheirer.identifier.Role; +import io.github.dsheirer.identifier.string.StringListIdentifier; + +import java.util.List; + +/** + * Knox tones identifier + */ +public abstract class KnoxIdentifier extends StringListIdentifier +{ + public KnoxIdentifier(List values) + { + super(values, IdentifierClass.USER, Form.KNOX_TONE, Role.TO); + } + + @Override + public String toString() + { + return "KNOX:" + Joiner.on("").join(getValue()); + } +} diff --git a/src/main/java/io/github/dsheirer/identifier/tone/P25CallProgressIdentifier.java b/src/main/java/io/github/dsheirer/identifier/tone/P25CallProgressIdentifier.java new file mode 100644 index 000000000..129c37eb2 --- /dev/null +++ b/src/main/java/io/github/dsheirer/identifier/tone/P25CallProgressIdentifier.java @@ -0,0 +1,46 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.identifier.tone; + +import io.github.dsheirer.protocol.Protocol; + +import java.util.List; + +public class P25CallProgressIdentifier extends CallProgressIdentifier +{ + public P25CallProgressIdentifier(List values) + { + super(values); + } + + @Override + public Protocol getProtocol() + { + return Protocol.APCO25; + } + + public static P25CallProgressIdentifier create(List values) + { + return new P25CallProgressIdentifier(values); + } +} diff --git a/src/main/java/io/github/dsheirer/identifier/tone/P25DtmfIdentifier.java b/src/main/java/io/github/dsheirer/identifier/tone/P25DtmfIdentifier.java new file mode 100644 index 000000000..1f3ed7d2b --- /dev/null +++ b/src/main/java/io/github/dsheirer/identifier/tone/P25DtmfIdentifier.java @@ -0,0 +1,46 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.identifier.tone; + +import io.github.dsheirer.protocol.Protocol; + +import java.util.List; + +public class P25DtmfIdentifier extends DtmfIdentifier +{ + public P25DtmfIdentifier(List values) + { + super(values); + } + + @Override + public Protocol getProtocol() + { + return Protocol.APCO25; + } + + public static P25DtmfIdentifier create(List values) + { + return new P25DtmfIdentifier(values); + } +} diff --git a/src/main/java/io/github/dsheirer/identifier/tone/P25KnoxIdentifier.java b/src/main/java/io/github/dsheirer/identifier/tone/P25KnoxIdentifier.java new file mode 100644 index 000000000..e952fdc86 --- /dev/null +++ b/src/main/java/io/github/dsheirer/identifier/tone/P25KnoxIdentifier.java @@ -0,0 +1,46 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.identifier.tone; + +import io.github.dsheirer.protocol.Protocol; + +import java.util.List; + +public class P25KnoxIdentifier extends KnoxIdentifier +{ + public P25KnoxIdentifier(List values) + { + super(values); + } + + @Override + public Protocol getProtocol() + { + return Protocol.APCO25; + } + + public static P25KnoxIdentifier create(List values) + { + return new P25KnoxIdentifier(values); + } +} diff --git a/src/main/java/io/github/dsheirer/identifier/tone/P25ToneIdentifier.java b/src/main/java/io/github/dsheirer/identifier/tone/P25ToneIdentifier.java new file mode 100644 index 000000000..26ef0b6e2 --- /dev/null +++ b/src/main/java/io/github/dsheirer/identifier/tone/P25ToneIdentifier.java @@ -0,0 +1,46 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.identifier.tone; + +import io.github.dsheirer.protocol.Protocol; + +import java.util.List; + +public class P25ToneIdentifier extends ToneIdentifier +{ + public P25ToneIdentifier(List values) + { + super(values); + } + + @Override + public Protocol getProtocol() + { + return Protocol.APCO25; + } + + public static P25ToneIdentifier create(List values) + { + return new P25ToneIdentifier(values); + } +} diff --git a/src/main/java/io/github/dsheirer/identifier/tone/ToneIdentifier.java b/src/main/java/io/github/dsheirer/identifier/tone/ToneIdentifier.java new file mode 100644 index 000000000..39a5799ff --- /dev/null +++ b/src/main/java/io/github/dsheirer/identifier/tone/ToneIdentifier.java @@ -0,0 +1,48 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.identifier.tone; + +import com.google.common.base.Joiner; +import io.github.dsheirer.identifier.Form; +import io.github.dsheirer.identifier.IdentifierClass; +import io.github.dsheirer.identifier.Role; +import io.github.dsheirer.identifier.string.StringListIdentifier; + +import java.util.List; + +/** + * Pass-band audio tones identifier + */ +public abstract class ToneIdentifier extends StringListIdentifier +{ + public ToneIdentifier(List values) + { + super(values, IdentifierClass.USER, Form.TONE, Role.TO); + } + + @Override + public String toString() + { + return "TONES:" + Joiner.on("").join(getValue()); + } +} diff --git a/src/main/java/io/github/dsheirer/message/IMessage.java b/src/main/java/io/github/dsheirer/message/IMessage.java index 6af72d71d..6e729952b 100644 --- a/src/main/java/io/github/dsheirer/message/IMessage.java +++ b/src/main/java/io/github/dsheirer/message/IMessage.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.message; import io.github.dsheirer.identifier.Identifier; @@ -38,6 +44,12 @@ public interface IMessage */ Protocol getProtocol(); + /** + * Indicates the timeslot for the message + * @return timeslot (0-based) + */ + int getTimeslot(); + /** * List of identifiers present in the message * @return list of identifiers or an empty list diff --git a/src/main/java/io/github/dsheirer/message/Message.java b/src/main/java/io/github/dsheirer/message/Message.java index 57ead0df9..00fe20d87 100644 --- a/src/main/java/io/github/dsheirer/message/Message.java +++ b/src/main/java/io/github/dsheirer/message/Message.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.message; import io.github.dsheirer.protocol.Protocol; @@ -61,6 +67,14 @@ public long getTimestamp() */ public abstract boolean isValid(); + /** + * Timeslot default of 0 unless override in subclass. + */ + public int getTimeslot() + { + return 0; + } + /** * Decoded protocol */ diff --git a/src/main/java/io/github/dsheirer/message/MessageInjectionModule.java b/src/main/java/io/github/dsheirer/message/MessageInjectionModule.java new file mode 100644 index 000000000..1f26be35d --- /dev/null +++ b/src/main/java/io/github/dsheirer/message/MessageInjectionModule.java @@ -0,0 +1,83 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.message; + +import io.github.dsheirer.module.Module; +import io.github.dsheirer.sample.Listener; + +/** + * Testing module to use for injecting IMessages into a processing chain + */ +public class MessageInjectionModule extends Module implements IMessageProvider +{ + private Listener mMessageListener; + + public MessageInjectionModule() + { + + } + + @Override + public void reset() + { + + } + + @Override + public void start() + { + + } + + @Override + public void stop() + { + + } + + @Override + public void dispose() + { + + } + + public void receive(IMessage message) + { + if(mMessageListener != null) + { + mMessageListener.receive(message); + } + } + + @Override + public void setMessageListener(Listener listener) + { + mMessageListener = listener; + } + + @Override + public void removeMessageListener() + { + mMessageListener = null; + } +} diff --git a/src/main/java/io/github/dsheirer/module/ProcessingChain.java b/src/main/java/io/github/dsheirer/module/ProcessingChain.java index 9b404b254..445291ca9 100644 --- a/src/main/java/io/github/dsheirer/module/ProcessingChain.java +++ b/src/main/java/io/github/dsheirer/module/ProcessingChain.java @@ -1,35 +1,40 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module; import io.github.dsheirer.alias.AliasModel; import io.github.dsheirer.audio.IAudioPacketListener; import io.github.dsheirer.audio.IAudioPacketProvider; +import io.github.dsheirer.audio.codec.mbe.MBECallSequenceRecorder; import io.github.dsheirer.audio.squelch.ISquelchStateListener; import io.github.dsheirer.audio.squelch.ISquelchStateProvider; -import io.github.dsheirer.audio.squelch.SquelchState; -import io.github.dsheirer.channel.state.ChannelState; +import io.github.dsheirer.audio.squelch.SquelchStateEvent; +import io.github.dsheirer.channel.state.AbstractChannelState; import io.github.dsheirer.channel.state.DecoderState; import io.github.dsheirer.channel.state.DecoderStateEvent; import io.github.dsheirer.channel.state.IDecoderStateEventListener; import io.github.dsheirer.channel.state.IDecoderStateEventProvider; +import io.github.dsheirer.channel.state.MultiChannelState; +import io.github.dsheirer.channel.state.SingleChannelState; import io.github.dsheirer.controller.channel.Channel; import io.github.dsheirer.controller.channel.ChannelEvent; import io.github.dsheirer.controller.channel.IChannelEventListener; @@ -46,6 +51,7 @@ import io.github.dsheirer.module.decode.event.IDecodeEventProvider; import io.github.dsheirer.module.decode.event.MessageActivityModel; import io.github.dsheirer.module.log.EventLogger; +import io.github.dsheirer.record.binary.BinaryRecorder; import io.github.dsheirer.record.wave.ComplexBufferWaveRecorder; import io.github.dsheirer.sample.Broadcaster; import io.github.dsheirer.sample.Listener; @@ -108,14 +114,14 @@ public class ProcessingChain implements Listener private Broadcaster mIdentifierUpdateNotificationBroadcaster = new Broadcaster<>(); private Broadcaster mSourceEventBroadcaster = new Broadcaster<>(); private Broadcaster mMessageBroadcaster = new Broadcaster<>(); - private Broadcaster mSquelchStateBroadcaster = new Broadcaster<>(); + private Broadcaster mSquelchStateEventBroadcaster = new Broadcaster<>(); private AtomicBoolean mRunning = new AtomicBoolean(); protected Source mSource; private List mModules = new ArrayList<>(); private DecodeEventModel mDecodeEventModel; - private ChannelState mChannelState; + private AbstractChannelState mChannelState; private MessageActivityModel mMessageActivityModel; /** @@ -125,21 +131,28 @@ public class ProcessingChain implements Listener */ public ProcessingChain(Channel channel, AliasModel aliasModel) { - mChannelState = new ChannelState(channel, aliasModel); - addModule(mChannelState); + if(channel.getDecodeConfiguration().getTimeslotCount() == 1) + { + mChannelState = new SingleChannelState(channel, aliasModel); + } + else + { + mChannelState = new MultiChannelState(channel, aliasModel, channel.getDecodeConfiguration().getTimeslotCount()); + } + addModule(mChannelState); mDecodeEventModel = new DecodeEventModel(); addDecodeEventListener(mDecodeEventModel); } - public DecodeEventModel getDecodeEventModel() + public AbstractChannelState getChannelState() { - return mDecodeEventModel; + return mChannelState; } - public ChannelState getChannelState() + public DecodeEventModel getDecodeEventModel() { - return mChannelState; + return mDecodeEventModel; } public MessageActivityModel getMessageActivityModel() @@ -147,6 +160,10 @@ public MessageActivityModel getMessageActivityModel() return mMessageActivityModel; } + + //TODO: should we introduce the concept of getTimeslot() to messages and events and then use that to vector the + //TODO: inbound stream to the appropriate message and event models? + public void setMessageActivityModel(MessageActivityModel model) { mMessageActivityModel = model; @@ -171,7 +188,7 @@ public void dispose() mBasebandComplexBufferBroadcaster.dispose(); mDemodulatedBitstreamBufferBroadcaster.dispose(); mMessageBroadcaster.dispose(); - mSquelchStateBroadcaster.dispose(); + mSquelchStateEventBroadcaster.dispose(); } /** @@ -352,7 +369,7 @@ private void registerListeners(Module module) if(module instanceof ISquelchStateListener) { - mSquelchStateBroadcaster.addListener(((ISquelchStateListener)module).getSquelchStateListener()); + mSquelchStateEventBroadcaster.addListener(((ISquelchStateListener)module).getSquelchStateListener()); } } @@ -419,7 +436,7 @@ private void unregisterListeners(Module module) if(module instanceof ISquelchStateListener) { - mSquelchStateBroadcaster.removeListener(((ISquelchStateListener)module).getSquelchStateListener()); + mSquelchStateEventBroadcaster.removeListener(((ISquelchStateListener)module).getSquelchStateListener()); } } @@ -486,7 +503,7 @@ private void registerProviders(Module module) if(module instanceof ISquelchStateProvider) { - ((ISquelchStateProvider)module).setSquelchStateListener(mSquelchStateBroadcaster); + ((ISquelchStateProvider)module).setSquelchStateListener(mSquelchStateEventBroadcaster); } } @@ -691,6 +708,14 @@ public void removeRecordingModules() { recordingModules.add(module); } + else if(module instanceof MBECallSequenceRecorder) + { + recordingModules.add(module); + } + else if(module instanceof BinaryRecorder) + { + recordingModules.add(module); + } } for(Module recordingModule : recordingModules) @@ -806,14 +831,14 @@ public void removeFrequencyChangeListener(Listener listener) /** * Adds the listener to receive call events from all modules. */ - public void addSquelchStateListener(Listener listener) + public void addSquelchStateListener(Listener listener) { - mSquelchStateBroadcaster.addListener(listener); + mSquelchStateEventBroadcaster.addListener(listener); } - public void removeSquelchStateListener(Listener listener) + public void removeSquelchStateListener(Listener listener) { - mSquelchStateBroadcaster.removeListener(listener); + mSquelchStateEventBroadcaster.removeListener(listener); } /** diff --git a/src/main/java/io/github/dsheirer/module/decode/AuxDecodeConfigurationEditor.java b/src/main/java/io/github/dsheirer/module/decode/AuxDecodeConfigurationEditor.java index caee7e259..e09dd9e20 100644 --- a/src/main/java/io/github/dsheirer/module/decode/AuxDecodeConfigurationEditor.java +++ b/src/main/java/io/github/dsheirer/module/decode/AuxDecodeConfigurationEditor.java @@ -1,20 +1,24 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014-2016 Dennis Sheirer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - ******************************************************************************/ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ package io.github.dsheirer.module.decode; import io.github.dsheirer.controller.channel.Channel; @@ -22,11 +26,10 @@ import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration; import net.miginfocom.swing.MigLayout; -import javax.swing.*; +import javax.swing.JCheckBox; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; -import java.util.Collections; import java.util.List; public class AuxDecodeConfigurationEditor extends Editor @@ -34,118 +37,114 @@ public class AuxDecodeConfigurationEditor extends Editor private static final long serialVersionUID = 1L; private List mControls = new ArrayList<>(); - - public AuxDecodeConfigurationEditor() - { - init(); - } - - public AuxDecodeConfiguration getConfiguration() - { - return hasItem() ? getItem().getAuxDecodeConfiguration() : null; - } - - private void init() - { - setLayout( new MigLayout( "fill,wrap 4", "", "[][grow]" ) ); - - List decoders = DecoderType.getAuxDecoders(); - - Collections.sort( decoders ); - - for( DecoderType decoder: decoders ) - { - AuxDecoderCheckBox control = new AuxDecoderCheckBox( decoder ); - control.setEnabled( false ); - control.addActionListener( new ActionListener() - { - @Override - public void actionPerformed( ActionEvent e ) - { - setModified( true ); - } - } ); - add( control ); - mControls.add( control ); - } - } - - @Override + + public AuxDecodeConfigurationEditor() + { + init(); + } + + public AuxDecodeConfiguration getConfiguration() + { + return hasItem() ? getItem().getAuxDecodeConfiguration() : null; + } + + private void init() + { + setLayout(new MigLayout("fill,wrap 4", "", "[][grow]")); + + for(DecoderType decoder : DecoderType.AUX_DECODERS) + { + AuxDecoderCheckBox control = new AuxDecoderCheckBox(decoder); + control.setEnabled(false); + control.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + setModified(true); + } + }); + add(control); + mControls.add(control); + } + } + + @Override public void save() { - if( hasItem() ) - { - AuxDecodeConfiguration config = getItem().getAuxDecodeConfiguration(); - - config.clearAuxDecoders(); - - for( AuxDecoderCheckBox checkBox: mControls ) - { - if( checkBox.isSelected() ) - { - config.addAuxDecoder( checkBox.getDecoderType() ); - } - } - } - - setModified( false ); + if(hasItem()) + { + AuxDecodeConfiguration config = getItem().getAuxDecodeConfiguration(); + + config.clearAuxDecoders(); + + for(AuxDecoderCheckBox checkBox : mControls) + { + if(checkBox.isSelected()) + { + config.addAuxDecoder(checkBox.getDecoderType()); + } + } + } + + setModified(false); + } + + private void setControlsEnabled(boolean enabled) + { + for(AuxDecoderCheckBox box : mControls) + { + if(box.isEnabled() != enabled) + { + box.setEnabled(enabled); + } + } + } + + + public class AuxDecoderCheckBox extends JCheckBox + { + private static final long serialVersionUID = 1L; + + private DecoderType mDecoderType; + + public AuxDecoderCheckBox(DecoderType decoder) + { + super(decoder.getDisplayString()); + + mDecoderType = decoder; + } + + public DecoderType getDecoderType() + { + return mDecoderType; + } + } + + @Override + public void setItem(Channel channel) + { + super.setItem(channel); + + if(hasItem()) + { + setControlsEnabled(true); + + for(AuxDecoderCheckBox cb : mControls) + { + if(getItem().getAuxDecodeConfiguration().getAuxDecoders().contains(cb.getDecoderType())) + { + cb.setSelected(true); + } + else + { + cb.setSelected(false); + } + } + } + else + { + setControlsEnabled(false); + } } - - private void setControlsEnabled( boolean enabled ) - { - for( AuxDecoderCheckBox box: mControls ) - { - if( box.isEnabled() != enabled ) - { - box.setEnabled( enabled ); - } - } - } - - - public class AuxDecoderCheckBox extends JCheckBox - { - private static final long serialVersionUID = 1L; - - private DecoderType mDecoderType; - - public AuxDecoderCheckBox( DecoderType decoder ) - { - super( decoder.getDisplayString() ); - - mDecoderType = decoder; - } - - public DecoderType getDecoderType() - { - return mDecoderType; - } - } - - @Override - public void setItem( Channel channel ) - { - super.setItem( channel ); - - if( hasItem() ) - { - setControlsEnabled( true ); - - for( AuxDecoderCheckBox cb: mControls ) - { - if( getItem().getAuxDecodeConfiguration().getAuxDecoders().contains( cb.getDecoderType() ) ) - { - cb.setSelected( true ); - } - else - { - cb.setSelected( false ); - } - } - } - else - { - setControlsEnabled( false ); - } - } } diff --git a/src/main/java/io/github/dsheirer/module/decode/DecodeConfigurationEditor.java b/src/main/java/io/github/dsheirer/module/decode/DecodeConfigurationEditor.java index 7cfb1ba85..3bccad29f 100644 --- a/src/main/java/io/github/dsheirer/module/decode/DecodeConfigurationEditor.java +++ b/src/main/java/io/github/dsheirer/module/decode/DecodeConfigurationEditor.java @@ -1,20 +1,24 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014-2016 Dennis Sheirer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - ******************************************************************************/ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ package io.github.dsheirer.module.decode; import io.github.dsheirer.controller.channel.Channel; @@ -25,110 +29,111 @@ import io.github.dsheirer.gui.editor.ValidatingEditor; import net.miginfocom.swing.MigLayout; -import javax.swing.*; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class DecodeConfigurationEditor extends ValidatingEditor { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; private JComboBox mComboDecoders; - private ValidatingEditor mCurrentEditor = new EmptyValidatingEditor<>( "a decoder" ); + private ValidatingEditor mCurrentEditor = new EmptyValidatingEditor<>("a decoder"); private ChannelMapModel mChannelMapModel; - public DecodeConfigurationEditor( final ChannelMapModel channelMapModel ) - { - mChannelMapModel = channelMapModel; - init(); - } + public DecodeConfigurationEditor(final ChannelMapModel channelMapModel) + { + mChannelMapModel = channelMapModel; + init(); + } private void init() { - setLayout( new MigLayout( "wrap 2", "[][grow,fill]", "[align top][grow,fill]" ) ); - - mComboDecoders = new JComboBox(); - mComboDecoders.setEnabled( false ); - - DefaultComboBoxModel model = new DefaultComboBoxModel(); - - for( DecoderType type: DecoderType.getPrimaryDecoders() ) - { - model.addElement( type ); - } - - mComboDecoders.setModel( model ); - mComboDecoders.addActionListener( new ActionListener() - { - @Override - public void actionPerformed( ActionEvent e ) - { - DecoderType selected = mComboDecoders.getItemAt( mComboDecoders.getSelectedIndex() ); - ValidatingEditor editor = DecoderFactory.getEditor( selected, mChannelMapModel ); - setEditor( editor ); - } - }); - - add( mComboDecoders ); - add( mCurrentEditor ); + setLayout(new MigLayout("wrap 2", "[][grow,fill]", "[align top][grow,fill]")); + + mComboDecoders = new JComboBox(); + mComboDecoders.setEnabled(false); + + DefaultComboBoxModel model = new DefaultComboBoxModel(); + + for(DecoderType type : DecoderType.PRIMARY_DECODERS) + { + model.addElement(type); + } + + mComboDecoders.setModel(model); + mComboDecoders.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + DecoderType selected = mComboDecoders.getItemAt(mComboDecoders.getSelectedIndex()); + ValidatingEditor editor = DecoderFactory.getEditor(selected, mChannelMapModel); + setEditor(editor); + } + }); + + add(mComboDecoders); + add(mCurrentEditor); } - - private void setEditor( ValidatingEditor editor ) + + private void setEditor(ValidatingEditor editor) { - if( mCurrentEditor != editor ) - { - //Set channel to null in current editor to force a save prompt as required - if( mCurrentEditor.isModified() ) - { - mCurrentEditor.setItem( null ); - } - - remove( mCurrentEditor ); - - mCurrentEditor = editor; - mCurrentEditor.setSaveRequestListener( this ); - mCurrentEditor.setItem( getItem() ); - - add( mCurrentEditor ); - - revalidate(); - repaint(); - } + if(mCurrentEditor != editor) + { + //Set channel to null in current editor to force a save prompt as required + if(mCurrentEditor.isModified()) + { + mCurrentEditor.setItem(null); + } + + remove(mCurrentEditor); + + mCurrentEditor = editor; + mCurrentEditor.setSaveRequestListener(this); + mCurrentEditor.setItem(getItem()); + + add(mCurrentEditor); + + revalidate(); + repaint(); + } } @Override public void save() { - if( hasItem() ) - { - mCurrentEditor.save(); - } - - setModified( false ); + if(hasItem()) + { + mCurrentEditor.save(); + } + + setModified(false); } - @Override - public void setItem( Channel channel ) - { - super.setItem( channel ); - - if( hasItem() ) - { - mComboDecoders.setEnabled( true ); - mComboDecoders.setSelectedItem( channel.getDecodeConfiguration().getDecoderType() ); - mCurrentEditor.setItem( channel ); - } - else - { - mComboDecoders.setEnabled( false ); - } - - setModified( false ); - } - - @Override - public void validate( Editor editor ) throws EditorValidationException - { - mCurrentEditor.validate( editor ); - } + @Override + public void setItem(Channel channel) + { + super.setItem(channel); + + if(hasItem()) + { + mComboDecoders.setEnabled(true); + mComboDecoders.setSelectedItem(channel.getDecodeConfiguration().getDecoderType()); + mCurrentEditor.setItem(channel); + } + else + { + mComboDecoders.setEnabled(false); + } + + setModified(false); + } + + @Override + public void validate(Editor editor) throws EditorValidationException + { + mCurrentEditor.validate(editor); + } } diff --git a/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java b/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java index a505b51f9..1a4fe6f56 100644 --- a/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode; @@ -71,14 +73,19 @@ import io.github.dsheirer.module.decode.nbfm.DecodeConfigNBFM; import io.github.dsheirer.module.decode.nbfm.NBFMDecoder; import io.github.dsheirer.module.decode.nbfm.NBFMDecoderEditor; -import io.github.dsheirer.module.decode.p25.DecodeConfigP25Phase1; -import io.github.dsheirer.module.decode.p25.P25DecoderC4FM; -import io.github.dsheirer.module.decode.p25.P25DecoderEditor; -import io.github.dsheirer.module.decode.p25.P25DecoderLSM; -import io.github.dsheirer.module.decode.p25.P25DecoderState; import io.github.dsheirer.module.decode.p25.P25TrafficChannelManager; -import io.github.dsheirer.module.decode.p25.audio.P25AudioModule; -import io.github.dsheirer.module.decode.p25.message.filter.P25MessageFilterSet; +import io.github.dsheirer.module.decode.p25.audio.P25P1AudioModule; +import io.github.dsheirer.module.decode.p25.audio.P25P2AudioModule; +import io.github.dsheirer.module.decode.p25.phase1.DecodeConfigP25Phase1; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderC4FM; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderEditor; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderLSM; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderState; +import io.github.dsheirer.module.decode.p25.phase1.message.filter.P25MessageFilterSet; +import io.github.dsheirer.module.decode.p25.phase2.DecodeConfigP25Phase2; +import io.github.dsheirer.module.decode.p25.phase2.P25P2DecoderEditor; +import io.github.dsheirer.module.decode.p25.phase2.P25P2DecoderHDQPSK; +import io.github.dsheirer.module.decode.p25.phase2.P25P2DecoderState; import io.github.dsheirer.module.decode.passport.DecodeConfigPassport; import io.github.dsheirer.module.decode.passport.PassportDecoder; import io.github.dsheirer.module.decode.passport.PassportDecoderEditor; @@ -96,7 +103,6 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; -import java.util.EnumSet; import java.util.List; public class DecoderFactory @@ -150,14 +156,15 @@ public static List getPrimaryModules(ChannelMapModel channelMapModel, Ch case AM: modules.add(new AMDecoder(decodeConfig)); modules.add(new AlwaysUnsquelchedDecoderState(DecoderType.AM, channel.getName())); - AudioModule audioModuleAM = new AudioModule(); //Check if the user wants all audio recorded .. if(((DecodeConfigAM)decodeConfig).getRecordAudio()) { + AudioModule audioModuleAM = new AudioModule(); audioModuleAM.setRecordAudio(true); + modules.add(audioModuleAM); } - modules.add(audioModuleAM); + if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER) { modules.add(new AMDemodulatorModule(AM_CHANNEL_BANDWIDTH, DEMODULATED_AUDIO_SAMPLE_RATE)); @@ -247,10 +254,10 @@ public static List getPrimaryModules(ChannelMapModel channelMapModel, Ch switch(p25Config.getModulation()) { case C4FM: - modules.add(new P25DecoderC4FM()); + modules.add(new P25P1DecoderC4FM()); break; case CQPSK: - modules.add(new P25DecoderLSM()); + modules.add(new P25P1DecoderLSM()); break; default: throw new IllegalArgumentException("Unrecognized P25 Phase 1 Modulation [" + @@ -261,14 +268,14 @@ public static List getPrimaryModules(ChannelMapModel channelMapModel, Ch { P25TrafficChannelManager trafficChannelManager = new P25TrafficChannelManager(channel); modules.add(trafficChannelManager); - modules.add(new P25DecoderState(channel, trafficChannelManager)); + modules.add(new P25P1DecoderState(channel, trafficChannelManager)); } else { - modules.add(new P25DecoderState(channel)); + modules.add(new P25P1DecoderState(channel)); } - modules.add(new P25AudioModule(userPreferences)); + modules.add(new P25P1AudioModule(userPreferences)); //Add a channel rotation monitor when we have multiple control channel frequencies specified if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency && @@ -279,6 +286,14 @@ public static List getPrimaryModules(ChannelMapModel channelMapModel, Ch modules.add(new ChannelRotationMonitor(activeStates, userPreferences)); } break; + case P25_PHASE2: + 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)); + modules.add(new P25P2AudioModule(userPreferences, 1)); + break; default: throw new IllegalArgumentException("Unknown decoder type [" + decodeConfig.getDecoderType().toString() + "]"); } @@ -418,6 +433,8 @@ public static DecodeConfiguration getDecodeConfiguration(DecoderType decoder) return new DecodeConfigPassport(); case P25_PHASE1: return new DecodeConfigP25Phase1(); + case P25_PHASE2: + return new DecodeConfigP25Phase2(); default: throw new IllegalArgumentException("DecodeConfigFactory - unknown decoder type [" + decoder.toString() + "]"); } @@ -438,7 +455,9 @@ public static ValidatingEditor getEditor(DecoderType type, ChannelMapMo case NBFM: return new NBFMDecoderEditor(); case P25_PHASE1: - return new P25DecoderEditor(); + return new P25P1DecoderEditor(); + case P25_PHASE2: + return new P25P2DecoderEditor(); case PASSPORT: return new PassportDecoderEditor(); default: @@ -486,6 +505,15 @@ public static DecodeConfiguration copy(DecodeConfiguration config) copyP25.setModulation(originalP25.getModulation()); copyP25.setTrafficChannelPoolSize(originalP25.getTrafficChannelPoolSize()); return copyP25; + case P25_PHASE2: + DecodeConfigP25Phase2 originalP25P2 = (DecodeConfigP25Phase2)config; + DecodeConfigP25Phase2 copyP25P2 = new DecodeConfigP25Phase2(); + + if(originalP25P2.getScrambleParameters() != null) + { + copyP25P2.setScrambleParameters(originalP25P2.getScrambleParameters().copy()); + } + return copyP25P2; case PASSPORT: return new DecodeConfigPassport(); default: @@ -495,14 +523,4 @@ public static DecodeConfiguration copy(DecodeConfiguration config) return null; } - - /** - * Decoder(s) that support bitstreams indicating that they produce ReusableByteBuffers of decoded bits. - * - * @return set of decoders that support bitstreams. - */ - public static EnumSet getBitstreamDecoders() - { - return EnumSet.of(DecoderType.P25_PHASE1, DecoderType.MPT1327); - } } \ No newline at end of file diff --git a/src/main/java/io/github/dsheirer/module/decode/DecoderType.java b/src/main/java/io/github/dsheirer/module/decode/DecoderType.java index 1c7733d14..5f11a0cfa 100644 --- a/src/main/java/io/github/dsheirer/module/decode/DecoderType.java +++ b/src/main/java/io/github/dsheirer/module/decode/DecoderType.java @@ -1,27 +1,28 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode; import io.github.dsheirer.protocol.Protocol; -import java.util.ArrayList; import java.util.EnumSet; /** @@ -36,7 +37,8 @@ public enum DecoderType MPT1327("MPT1327", "MPT1327", Protocol.MPT1327), NBFM("NBFM", "NBFM", Protocol.UNKNOWN), PASSPORT("Passport", "Passport", Protocol.PASSPORT), - P25_PHASE1("P25 Phase I", "P25-1", Protocol.APCO25), + P25_PHASE1("P25 Phase 1", "P25-1", Protocol.APCO25), + P25_PHASE2("P25 Phase 2", "P25-2", Protocol.APCO25), //Auxiliary Decoders FLEETSYNC2("Fleetsync II", "Fleetsync2", Protocol.FLEETSYNC), @@ -56,33 +58,41 @@ public enum DecoderType } /** - * Primary decoders + * Primary decoders that operate on I/Q sample streams */ - public static EnumSet getPrimaryDecoders() - { - return EnumSet.of(DecoderType.AM, - DecoderType.LTR_NET, - DecoderType.LTR_STANDARD, - DecoderType.MPT1327, - DecoderType.NBFM, - DecoderType.P25_PHASE1, - DecoderType.PASSPORT); - } + public static EnumSet PRIMARY_DECODERS = + EnumSet.of(DecoderType.AM, + DecoderType.LTR_NET, + DecoderType.LTR_STANDARD, + DecoderType.MPT1327, + DecoderType.NBFM, + DecoderType.P25_PHASE1, + DecoderType.P25_PHASE2, + DecoderType.PASSPORT); /** - * Available auxiliary decoders. + * Auxiliary decoders that operate on in-band signalling in the decoded audio channel */ - public static ArrayList getAuxDecoders() - { - ArrayList decoders = new ArrayList(); + public static final EnumSet AUX_DECODERS = + EnumSet.of(DecoderType.FLEETSYNC2, + DecoderType.LJ_1200, + DecoderType.MDC1200, + DecoderType.TAIT_1200); - decoders.add(DecoderType.FLEETSYNC2); - decoders.add(DecoderType.LJ_1200); - decoders.add(DecoderType.MDC1200); - decoders.add(DecoderType.TAIT_1200); + /** + * Decoders that produce a (recordable) bitstream + */ + public static final EnumSet BITSTREAM_DECODERS = + EnumSet.of(DecoderType.MPT1327, + DecoderType.P25_PHASE1, + DecoderType.P25_PHASE2); - return decoders; - } + /** + * Decoders that produce (recordable) MBE audio codec frames + */ + public static final EnumSet MBE_AUDIO_CODEC_DECODERS = + EnumSet.of(DecoderType.P25_PHASE1, + DecoderType.P25_PHASE2); public Protocol getProtocol() { @@ -104,4 +114,20 @@ public String toString() { return mDisplayString; } + + /** + * Indicates if the decoder type produces a (recordable) bitstream + */ + public boolean providesBitstream() + { + return BITSTREAM_DECODERS.contains(this); + } + + /** + * Indicates if the decoder type produces (recordable) MBE audio codec frames + */ + public boolean providesMBEAudioFrames() + { + return MBE_AUDIO_CODEC_DECODERS.contains(this); + } } diff --git a/src/main/java/io/github/dsheirer/module/decode/PrimaryDecoder.java b/src/main/java/io/github/dsheirer/module/decode/PrimaryDecoder.java index be4826fb4..da441c300 100644 --- a/src/main/java/io/github/dsheirer/module/decode/PrimaryDecoder.java +++ b/src/main/java/io/github/dsheirer/module/decode/PrimaryDecoder.java @@ -1,76 +1,80 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2015 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 - ******************************************************************************/ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ package io.github.dsheirer.module.decode; import io.github.dsheirer.audio.squelch.ISquelchStateProvider; -import io.github.dsheirer.audio.squelch.SquelchState; +import io.github.dsheirer.audio.squelch.SquelchStateEvent; import io.github.dsheirer.module.decode.config.DecodeConfiguration; import io.github.dsheirer.sample.Listener; /** * Primary decoder adds the following functionality over the basic decoder: - * + * * - Provides audio squelch control */ public abstract class PrimaryDecoder extends Decoder implements ISquelchStateProvider { - protected Listener mSquelchStateListener; - - protected DecodeConfiguration mDecodeConfiguration; - - public PrimaryDecoder( DecodeConfiguration config ) - { - mDecodeConfiguration = config; - } - - public DecodeConfiguration getDecodeConfiguration() - { - return mDecodeConfiguration; - } - - @Override - public void dispose() - { - super.dispose(); - - mSquelchStateListener = null; - mDecodeConfiguration = null; - } + protected Listener mSquelchStateListener; + + protected DecodeConfiguration mDecodeConfiguration; + + public PrimaryDecoder(DecodeConfiguration config) + { + mDecodeConfiguration = config; + } + + public DecodeConfiguration getDecodeConfiguration() + { + return mDecodeConfiguration; + } + + @Override + public void dispose() + { + super.dispose(); + + mSquelchStateListener = null; + mDecodeConfiguration = null; + } + + public void broadcast(SquelchStateEvent state) + { + if(mSquelchStateListener != null) + { + mSquelchStateListener.receive(state); + } + } - public void broadcast( SquelchState state ) - { - if( mSquelchStateListener != null ) - { - mSquelchStateListener.receive( state ); - } - } - - @Override - public void setSquelchStateListener( Listener listener ) - { - mSquelchStateListener = listener; - } + @Override + public void setSquelchStateListener(Listener listener) + { + mSquelchStateListener = listener; + } - @Override - public void removeSquelchStateListener() - { - mSquelchStateListener = null; - } + @Override + public void removeSquelchStateListener() + { + mSquelchStateListener = null; + } } diff --git a/src/main/java/io/github/dsheirer/module/decode/config/DecodeConfiguration.java b/src/main/java/io/github/dsheirer/module/decode/config/DecodeConfiguration.java index 2d6bd76da..c24e6f521 100644 --- a/src/main/java/io/github/dsheirer/module/decode/config/DecodeConfiguration.java +++ b/src/main/java/io/github/dsheirer/module/decode/config/DecodeConfiguration.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.module.decode.config; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -27,7 +33,8 @@ 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.DecodeConfigP25Phase1; +import io.github.dsheirer.module.decode.p25.phase1.DecodeConfigP25Phase1; +import io.github.dsheirer.module.decode.p25.phase2.DecodeConfigP25Phase2; import io.github.dsheirer.module.decode.passport.DecodeConfigPassport; import io.github.dsheirer.source.tuner.channel.ChannelSpecification; @@ -40,12 +47,13 @@ @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 = DecodeConfigPassport.class, name = "decodeConfigPassport") }) @JacksonXmlRootElement(localName = "decode_configuration") public abstract class DecodeConfiguration extends Configuration { - public static final int DEFAULT_CALL_TIMEOUT_SECONDS = 45; + 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 = 300; //5 minutes @@ -62,4 +70,10 @@ public DecodeConfiguration() @JsonIgnore public abstract ChannelSpecification getChannelSpecification(); + + @JsonIgnore + public int getTimeslotCount() + { + return 1; + } } diff --git a/src/main/java/io/github/dsheirer/module/decode/event/DecodeEvent.java b/src/main/java/io/github/dsheirer/module/decode/event/DecodeEvent.java index cfd6e0790..831ca54c6 100644 --- a/src/main/java/io/github/dsheirer/module/decode/event/DecodeEvent.java +++ b/src/main/java/io/github/dsheirer/module/decode/event/DecodeEvent.java @@ -1,25 +1,28 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.event; +import com.google.common.base.Joiner; import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.identifier.IdentifierCollection; import io.github.dsheirer.protocol.Protocol; @@ -37,6 +40,7 @@ public class DecodeEvent implements IDecodeEvent private IChannelDescriptor mChannelDescriptor; private String mDetails; private Protocol mProtocol; + private Integer mTimeslot; public DecodeEvent(long start) { @@ -187,6 +191,49 @@ public void setProtocol(Protocol protocol) mProtocol = protocol; } + /** + * Timeslot for this event + * @return timeslot or default value of 0 + */ + @Override + public Integer getTimeslot() + { + return mTimeslot; + } + + /** + * Indicates if this event specifies a timeslot + */ + public boolean hasTimeslot() + { + return mTimeslot != null; + } + + /** + * Sets the timeslot for this event + * @param timeslot of the event + */ + public void setTimeslot(Integer timeslot) + { + mTimeslot = timeslot; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(mProtocol); + sb.append(" DECODE EVENT: ").append(getEventDescription()); + sb.append(" DETAILS:").append(getDetails()); + if(mIdentifierCollection != null) + { + sb.append(" IDS:").append(Joiner.on(",").join(mIdentifierCollection.getIdentifiers())); + } + sb.append(" DURATION:").append(mDuration); + sb.append(" CHANNEL:").append(mChannelDescriptor); + return sb.toString(); + } + /** * Builder pattern for constructing decode events. */ @@ -199,6 +246,7 @@ public static class DecodeEventBuilder protected IChannelDescriptor mChannelDescriptor; protected String mDetails; protected Protocol mProtocol = Protocol.UNKNOWN; + protected Integer mTimeslot; /** * Constructs a builder instance with the specified start time in milliseconds @@ -279,6 +327,12 @@ public DecodeEventBuilder protocol(Protocol protocol) return this; } + public DecodeEventBuilder timeslot(Integer timeslot) + { + mTimeslot = timeslot; + return this; + } + /** * Builds the decode event */ @@ -291,6 +345,7 @@ public DecodeEvent build() decodeEvent.setEventDescription(mEventDescription); decodeEvent.setIdentifierCollection(mIdentifierCollection); decodeEvent.setProtocol(mProtocol); + decodeEvent.setTimeslot(mTimeslot); return decodeEvent; } } diff --git a/src/main/java/io/github/dsheirer/module/decode/event/DecodeEventModel.java b/src/main/java/io/github/dsheirer/module/decode/event/DecodeEventModel.java index 917e98be4..17e27247f 100644 --- a/src/main/java/io/github/dsheirer/module/decode/event/DecodeEventModel.java +++ b/src/main/java/io/github/dsheirer/module/decode/event/DecodeEventModel.java @@ -1,20 +1,24 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014,2015 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - ******************************************************************************/ + */ package io.github.dsheirer.module.decode.event; import com.google.common.eventbus.Subscribe; @@ -184,7 +188,30 @@ public Object getValueAt(int rowIndex, int columnIndex) case COLUMN_TO_ALIAS: return event.getIdentifierCollection(); case COLUMN_CHANNEL: - return event.getChannelDescriptor(); + IChannelDescriptor channelDescriptor = event.getChannelDescriptor(); + + if(channelDescriptor != null) + { + if(event.hasTimeslot()) + { + return channelDescriptor.toString() + " TS:" + event.getTimeslot(); + } + else + { + return channelDescriptor.toString(); + } + } + else + { + if(event.hasTimeslot()) + { + return "TS:" + event.getTimeslot(); + } + else + { + return null; + } + } case COLUMN_FREQUENCY: return event.getChannelDescriptor(); case COLUMN_DETAILS: @@ -214,7 +241,7 @@ public Class getColumnClass(int columnIndex) case COLUMN_TO_ID: return IdentifierCollection.class; case COLUMN_CHANNEL: - return IChannelDescriptor.class; + return String.class; } return super.getColumnClass(columnIndex); diff --git a/src/main/java/io/github/dsheirer/module/decode/event/DecodeEventPanel.java b/src/main/java/io/github/dsheirer/module/decode/event/DecodeEventPanel.java index dab408e0c..8025a086f 100644 --- a/src/main/java/io/github/dsheirer/module/decode/event/DecodeEventPanel.java +++ b/src/main/java/io/github/dsheirer/module/decode/event/DecodeEventPanel.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.event; @@ -106,7 +108,6 @@ public void preferenceUpdated(PreferenceType preferenceType) } } - private void updateCellRenderers() { mTable.getColumnModel().getColumn(DecodeEventModel.COLUMN_TIME) @@ -356,7 +357,7 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole */ public class FrequencyCellRenderer extends DefaultTableCellRenderer { - private DecimalFormat mFrequencyFormatter = new DecimalFormat("0.00000 MHz"); + private DecimalFormat mFrequencyFormatter = new DecimalFormat("0.00000"); public FrequencyCellRenderer() { @@ -397,22 +398,5 @@ public ChannelDescriptorCellRenderer() { setHorizontalAlignment(JLabel.CENTER); } - - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) - { - JLabel label = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - - if(value instanceof IChannelDescriptor) - { - label.setText(value.toString()); - } - else - { - label.setText(null); - } - - return label; - } } } diff --git a/src/main/java/io/github/dsheirer/module/decode/event/IDecodeEvent.java b/src/main/java/io/github/dsheirer/module/decode/event/IDecodeEvent.java index 722c72dab..66551c44f 100644 --- a/src/main/java/io/github/dsheirer/module/decode/event/IDecodeEvent.java +++ b/src/main/java/io/github/dsheirer/module/decode/event/IDecodeEvent.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.event; @@ -71,4 +73,15 @@ public interface IDecodeEvent * Protocol for the decoder that produced the event */ Protocol getProtocol(); + + /** + * Timeslot for the event. + * @return timeslot or default of 0 + */ + Integer getTimeslot(); + + /** + * Indicates if the event has a timeslot specified + */ + boolean hasTimeslot(); } diff --git a/src/main/java/io/github/dsheirer/module/decode/event/MessageActivityModel.java b/src/main/java/io/github/dsheirer/module/decode/event/MessageActivityModel.java index 25a10e082..3fb2cf1c4 100644 --- a/src/main/java/io/github/dsheirer/module/decode/event/MessageActivityModel.java +++ b/src/main/java/io/github/dsheirer/module/decode/event/MessageActivityModel.java @@ -1,20 +1,24 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014-2016 Dennis Sheirer +/* * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - ******************************************************************************/ + */ package io.github.dsheirer.module.decode.event; import io.github.dsheirer.filter.FilterSet; @@ -31,12 +35,13 @@ public class MessageActivityModel extends AbstractTableModel implements Listener private static final long serialVersionUID = 1L; private static final int TIME = 0; private static final int PROTOCOL = 1; - private static final int MESSAGE = 2; + private static final int TIMESLOT = 2; + private static final int MESSAGE = 3; protected int mMaxMessages = 500; protected LinkedList mMessageItems = new LinkedList<>(); protected int[] mColumnWidths = {20, 20, 500}; - protected String[] mHeaders = new String[]{"Time", "Protocol", "Message"}; + protected String[] mHeaders = new String[]{"Time", "Protocol", "Timeslot", "Message"}; private SimpleDateFormat mSDFTime = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"); @@ -168,6 +173,8 @@ public Object getValueAt(int rowIndex, int columnIndex) return messageItem.getTimestamp(mSDFTime); case PROTOCOL: return messageItem.getProtocol(); + case TIMESLOT: + return messageItem.getTimeslot(); case MESSAGE: return messageItem.getText(); default: diff --git a/src/main/java/io/github/dsheirer/module/decode/event/MessageItem.java b/src/main/java/io/github/dsheirer/module/decode/event/MessageItem.java index df669c9ba..686d2e702 100644 --- a/src/main/java/io/github/dsheirer/module/decode/event/MessageItem.java +++ b/src/main/java/io/github/dsheirer/module/decode/event/MessageItem.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.event; @@ -67,6 +69,11 @@ public String getTimestamp(SimpleDateFormat simpleDateFormat) return mTimestamp; } + public int getTimeslot() + { + return mMessage.getTimeslot(); + } + public String getText() { if(mText == null) diff --git a/src/main/java/io/github/dsheirer/module/decode/fleetsync2/Fleetsync2DecoderState.java b/src/main/java/io/github/dsheirer/module/decode/fleetsync2/Fleetsync2DecoderState.java index a822230b8..00a05455c 100644 --- a/src/main/java/io/github/dsheirer/module/decode/fleetsync2/Fleetsync2DecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/fleetsync2/Fleetsync2DecoderState.java @@ -1,21 +1,24 @@ -/******************************************************************************* - * sdrtrunk - * Copyright (C) 2014-2017 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.module.decode.fleetsync2; import io.github.dsheirer.channel.state.DecoderState; @@ -56,6 +59,7 @@ public DecoderType getDecoderType() @Override public void reset() { + super.reset(); mIdents.clear(); } diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/PacketMessageFactory.java b/src/main/java/io/github/dsheirer/module/decode/ip/PacketMessageFactory.java index fc4ee771e..81b771bd6 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ip/PacketMessageFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/ip/PacketMessageFactory.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -25,7 +25,7 @@ import io.github.dsheirer.module.decode.ip.ipv4.IPV4Header; import io.github.dsheirer.module.decode.ip.ipv4.IPV4Packet; import io.github.dsheirer.module.decode.ip.udp.UDPPacket; -import io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp.SNDCPPacketHeader; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPPacketHeader; import io.github.dsheirer.module.decode.p25.reference.IPHeaderCompression; /** diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/UnknownCompressedHeaderPacket.java b/src/main/java/io/github/dsheirer/module/decode/ip/UnknownCompressedHeaderPacket.java index e8fe2b596..37100ed60 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ip/UnknownCompressedHeaderPacket.java +++ b/src/main/java/io/github/dsheirer/module/decode/ip/UnknownCompressedHeaderPacket.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -21,7 +21,7 @@ package io.github.dsheirer.module.decode.ip; import io.github.dsheirer.bits.BinaryMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp.SNDCPPacketHeader; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPPacketHeader; public class UnknownCompressedHeaderPacket implements IPacket { diff --git a/src/main/java/io/github/dsheirer/module/decode/lj1200/LJ1200DecoderState.java b/src/main/java/io/github/dsheirer/module/decode/lj1200/LJ1200DecoderState.java index 18b156d62..65c223494 100644 --- a/src/main/java/io/github/dsheirer/module/decode/lj1200/LJ1200DecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/lj1200/LJ1200DecoderState.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.lj1200; @@ -144,6 +146,7 @@ protected void resetState() @Override public void reset() { + super.reset(); mAddresses.clear(); resetState(); } diff --git a/src/main/java/io/github/dsheirer/module/decode/ltrnet/LTRNetDecoderState.java b/src/main/java/io/github/dsheirer/module/decode/ltrnet/LTRNetDecoderState.java index a73c1fc75..a3bde96cf 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ltrnet/LTRNetDecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/ltrnet/LTRNetDecoderState.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.ltrnet; @@ -113,6 +115,7 @@ protected IChannelDescriptor getCurrentChannel() */ public void reset() { + super.reset(); mChannelMapHigh = null; mChannelMapLow = null; mChannelMap.clear(); diff --git a/src/main/java/io/github/dsheirer/module/decode/ltrnet/channel/LtrNetChannel.java b/src/main/java/io/github/dsheirer/module/decode/ltrnet/channel/LtrNetChannel.java index df753ccfc..fe27b3e73 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ltrnet/channel/LtrNetChannel.java +++ b/src/main/java/io/github/dsheirer/module/decode/ltrnet/channel/LtrNetChannel.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -21,7 +21,7 @@ package io.github.dsheirer.module.decode.ltrnet.channel; import io.github.dsheirer.channel.IChannelDescriptor; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; import io.github.dsheirer.protocol.Protocol; public class LtrNetChannel implements IChannelDescriptor, Comparable diff --git a/src/main/java/io/github/dsheirer/module/decode/ltrstandard/LTRStandardDecoderState.java b/src/main/java/io/github/dsheirer/module/decode/ltrstandard/LTRStandardDecoderState.java index 8d3d6bf5a..1518d1f2d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ltrstandard/LTRStandardDecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/ltrstandard/LTRStandardDecoderState.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.ltrstandard; @@ -147,6 +149,7 @@ public void receive(IMessage message) */ public void reset() { + super.reset(); mActiveCalls.clear(); mTalkgroupsFirstHeard.clear(); mTalkgroups.clear(); diff --git a/src/main/java/io/github/dsheirer/module/decode/ltrstandard/channel/LtrChannel.java b/src/main/java/io/github/dsheirer/module/decode/ltrstandard/channel/LtrChannel.java index a6767d79b..2e946a407 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ltrstandard/channel/LtrChannel.java +++ b/src/main/java/io/github/dsheirer/module/decode/ltrstandard/channel/LtrChannel.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -21,7 +21,7 @@ package io.github.dsheirer.module.decode.ltrstandard.channel; import io.github.dsheirer.channel.IChannelDescriptor; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; import io.github.dsheirer.protocol.Protocol; public class LtrChannel implements IChannelDescriptor, Comparable diff --git a/src/main/java/io/github/dsheirer/module/decode/mdc1200/MDCDecoderState.java b/src/main/java/io/github/dsheirer/module/decode/mdc1200/MDCDecoderState.java index 6997e0e9d..ae4d55059 100644 --- a/src/main/java/io/github/dsheirer/module/decode/mdc1200/MDCDecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/mdc1200/MDCDecoderState.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.mdc1200; @@ -52,6 +54,7 @@ public DecoderType getDecoderType() @Override public void reset() { + super.reset(); mIdents.clear(); mEmergencyIdents.clear(); diff --git a/src/main/java/io/github/dsheirer/module/decode/mpt1327/DecodeConfigMPT1327.java b/src/main/java/io/github/dsheirer/module/decode/mpt1327/DecodeConfigMPT1327.java index 0843742c7..d6cf458fa 100644 --- a/src/main/java/io/github/dsheirer/module/decode/mpt1327/DecodeConfigMPT1327.java +++ b/src/main/java/io/github/dsheirer/module/decode/mpt1327/DecodeConfigMPT1327.java @@ -1,20 +1,24 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014 Dennis Sheirer +/* * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - ******************************************************************************/ + */ package io.github.dsheirer.module.decode.mpt1327; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -28,7 +32,7 @@ public class DecodeConfigMPT1327 extends DecodeConfiguration private String mChannelMapName; private Sync mSync = Sync.NORMAL; - private int mCallTimeout = DEFAULT_CALL_TIMEOUT_SECONDS; + private int mCallTimeout = DEFAULT_CALL_TIMEOUT_DELAY_SECONDS; private int mTrafficChannelPoolSize = TRAFFIC_CHANNEL_LIMIT_DEFAULT; public DecodeConfigMPT1327() @@ -82,7 +86,7 @@ public void setCallTimeout(int timeout) } else { - mCallTimeout = DEFAULT_CALL_TIMEOUT_SECONDS; + mCallTimeout = DEFAULT_CALL_TIMEOUT_DELAY_SECONDS; } } diff --git a/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderEditor.java b/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderEditor.java index c7dd837a1..b58c38970 100644 --- a/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderEditor.java +++ b/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderEditor.java @@ -1,21 +1,24 @@ -/******************************************************************************* - * sdrtrunk - * Copyright (C) 2014-2017 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.module.decode.mpt1327; import io.github.dsheirer.controller.channel.Channel; @@ -114,7 +117,7 @@ public void stateChanged(ChangeEvent e) add(mTrafficChannelPoolSize); mCallTimeout = new JSlider(JSlider.HORIZONTAL, DecodeConfiguration.CALL_TIMEOUT_MINIMUM, - DecodeConfiguration.CALL_TIMEOUT_MAXIMUM, DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS); + DecodeConfiguration.CALL_TIMEOUT_MAXIMUM, DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS); mCallTimeout.setEnabled(false); mCallTimeout.setMajorTickSpacing(100); mCallTimeout.setMinorTickSpacing(50); @@ -211,7 +214,7 @@ public void setItem(Channel item) else { mTrafficChannelPoolSize.setValue(DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT); - mCallTimeout.setValue(DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS); + mCallTimeout.setValue(DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS); setModified(true); } diff --git a/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderState.java b/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderState.java index b4280602e..8077263d0 100644 --- a/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderState.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.mpt1327; @@ -270,8 +272,8 @@ public void receive(IMessage message) public void reset() { + super.reset(); mIdents.clear(); - resetState(); } @@ -306,7 +308,7 @@ protected void resetState() if(mChannelType == ChannelType.STANDARD) { broadcast(new ChangeChannelTimeoutEvent(this, mChannelType, - DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS * 1000)); + DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS * 1000)); } } diff --git a/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327Message.java b/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327Message.java index 6d3df6f98..495a199f4 100644 --- a/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327Message.java +++ b/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327Message.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.mpt1327; @@ -1075,105 +1077,65 @@ public String getSDMBinary(MPTMessageType type, SDMFormat format) case HEAD_PLUS1: if(format == SDMFormat.MPT1327) { - sb.append(mMessage.getHex(B2_SDM_STF0_START, - B2_SDM_STF0_END, - 12)); + sb.append(mMessage.getHex(B2_SDM_STF0_START, B2_SDM_STF0_END)); } else { - sb.append(mMessage.getHex(B2_SDM_STF1_START, - B2_SDM_STF1_END, - 12)); + sb.append(mMessage.getHex(B2_SDM_STF1_START, B2_SDM_STF1_END)); } break; case HEAD_PLUS2: if(format == SDMFormat.MPT1327) { - sb.append(mMessage.getHex(B2_SDM_STF0_START, - B2_SDM_STF0_END, - 12)); + sb.append(mMessage.getHex(B2_SDM_STF0_START, B2_SDM_STF0_END)); sb.append(" "); - sb.append(mMessage.getHex(B3_SDM_START, - B3_SDM_END, - 12)); + sb.append(mMessage.getHex(B3_SDM_START, B3_SDM_END)); } else { - sb.append(mMessage.getHex(B2_SDM_STF1_START, - B2_SDM_STF1_END, - 12)); + sb.append(mMessage.getHex(B2_SDM_STF1_START, B2_SDM_STF1_END)); sb.append(" "); - sb.append(mMessage.getHex(B3_SDM_START, - B3_SDM_END, - 12)); + sb.append(mMessage.getHex(B3_SDM_START, B3_SDM_END)); } break; case HEAD_PLUS3: if(format == SDMFormat.MPT1327) { - sb.append(mMessage.getHex(B2_SDM_STF0_START, - B2_SDM_STF0_END, - 12)); + sb.append(mMessage.getHex(B2_SDM_STF0_START, B2_SDM_STF0_END)); sb.append(" "); - sb.append(mMessage.getHex(B3_SDM_START, - B3_SDM_END, - 12)); + sb.append(mMessage.getHex(B3_SDM_START, B3_SDM_END)); sb.append(" "); - sb.append(mMessage.getHex(B4_SDM_STF0_START, - B4_SDM_STF0_END, - 12)); + sb.append(mMessage.getHex(B4_SDM_STF0_START, B4_SDM_STF0_END)); } else { - sb.append(mMessage.getHex(B2_SDM_STF1_START, - B2_SDM_STF1_END, - 12)); + sb.append(mMessage.getHex(B2_SDM_STF1_START, B2_SDM_STF1_END)); sb.append(" "); - sb.append(mMessage.getHex(B3_SDM_START, - B3_SDM_END, - 12)); + sb.append(mMessage.getHex(B3_SDM_START, B3_SDM_END)); sb.append(" "); - sb.append(mMessage.getHex(B4_SDM_STF1_START, - B4_SDM_STF1_END, - 12)); + sb.append(mMessage.getHex(B4_SDM_STF1_START, B4_SDM_STF1_END)); } break; case HEAD_PLUS4: if(format == SDMFormat.MPT1327) { - sb.append(mMessage.getHex(B2_SDM_STF0_START, - B2_SDM_STF0_END, - 12)); + sb.append(mMessage.getHex(B2_SDM_STF0_START, B2_SDM_STF0_END)); sb.append(" "); - sb.append(mMessage.getHex(B3_SDM_START, - B3_SDM_END, - 12)); + sb.append(mMessage.getHex(B3_SDM_START, B3_SDM_END)); sb.append(" "); - sb.append(mMessage.getHex(B4_SDM_STF0_START, - B4_SDM_STF0_END, - 12)); + sb.append(mMessage.getHex(B4_SDM_STF0_START, B4_SDM_STF0_END)); sb.append(" "); - sb.append(mMessage.getHex(B5_SDM_START, - B5_SDM_END, - 12)); + sb.append(mMessage.getHex(B5_SDM_START, B5_SDM_END)); } else { - sb.append(mMessage.getHex(B2_SDM_STF1_START, - B2_SDM_STF1_END, - 12)); + sb.append(mMessage.getHex(B2_SDM_STF1_START, B2_SDM_STF1_END)); sb.append(" "); - sb.append(mMessage.getHex(B3_SDM_START, - B3_SDM_END, - 12)); + sb.append(mMessage.getHex(B3_SDM_START, B3_SDM_END)); sb.append(" "); - sb.append(mMessage.getHex(B4_SDM_STF1_START, - B4_SDM_STF1_END, - 12)); + sb.append(mMessage.getHex(B4_SDM_STF1_START, B4_SDM_STF1_END)); sb.append(" "); - sb.append(mMessage.getHex(B5_SDM_START, - B5_SDM_END, - 12)); + sb.append(mMessage.getHex(B5_SDM_START, B5_SDM_END)); } break; default: diff --git a/src/main/java/io/github/dsheirer/module/decode/mpt1327/channel/MPT1327Channel.java b/src/main/java/io/github/dsheirer/module/decode/mpt1327/channel/MPT1327Channel.java index 36ac3c44e..f6c75562b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/mpt1327/channel/MPT1327Channel.java +++ b/src/main/java/io/github/dsheirer/module/decode/mpt1327/channel/MPT1327Channel.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -22,7 +22,7 @@ import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.controller.channel.map.ChannelMap; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; import io.github.dsheirer.protocol.Protocol; import java.util.Objects; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/C4FMFrameListener.java b/src/main/java/io/github/dsheirer/module/decode/p25/C4FMFrameListener.java deleted file mode 100644 index cbed79d8c..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/C4FMFrameListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.dsheirer.module.decode.p25; - -import io.github.dsheirer.bits.BinaryMessage; - -public interface C4FMFrameListener -{ - /** - * Listener interface to receive the output of the C4FMMessageFramer. - * - * @param buffer - framed message without the sync pattern - * @param inverted - flag indicating if the message was received inverted - */ - public void receive( BinaryMessage buffer, boolean inverted ); - -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25TrafficChannelManager.java b/src/main/java/io/github/dsheirer/module/decode/p25/P25TrafficChannelManager.java index bc08f3fe6..5bfac322e 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25TrafficChannelManager.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/P25TrafficChannelManager.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.p25; @@ -28,15 +30,29 @@ import io.github.dsheirer.controller.channel.IChannelEventProvider; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.identifier.IdentifierCollection; +import io.github.dsheirer.identifier.MutableIdentifierCollection; import io.github.dsheirer.identifier.Role; +import io.github.dsheirer.identifier.scramble.ScrambleParameterIdentifier; +import io.github.dsheirer.message.IMessage; +import io.github.dsheirer.message.IMessageListener; import io.github.dsheirer.module.Module; +import io.github.dsheirer.module.decode.DecoderType; import io.github.dsheirer.module.decode.config.DecodeConfiguration; import io.github.dsheirer.module.decode.event.DecodeEvent; import io.github.dsheirer.module.decode.event.DecodeEventType; import io.github.dsheirer.module.decode.event.IDecodeEvent; import io.github.dsheirer.module.decode.event.IDecodeEventProvider; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; +import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; +import io.github.dsheirer.module.decode.p25.identifier.channel.P25Channel; +import io.github.dsheirer.module.decode.p25.identifier.channel.P25P2Channel; +import io.github.dsheirer.module.decode.p25.identifier.channel.P25P2ExplicitChannel; +import io.github.dsheirer.module.decode.p25.phase1.DecodeConfigP25Phase1; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCNetworkStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.NetworkStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase2.DecodeConfigP25Phase2; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters; import io.github.dsheirer.module.decode.p25.reference.ServiceOptions; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.source.config.SourceConfigTuner; @@ -70,14 +86,17 @@ * This manager monitors channel events watching for events related to managed traffic channels. */ public class P25TrafficChannelManager extends Module implements IDecodeEventProvider, IChannelEventListener, - IChannelEventProvider + IChannelEventProvider, IMessageListener { private final static Logger mLog = LoggerFactory.getLogger(P25TrafficChannelManager.class); public static final String CHANNEL_START_REJECTED = "CHANNEL START REJECTED"; public static final String MAX_TRAFFIC_CHANNELS_EXCEEDED = "MAX TRAFFIC CHANNELS EXCEEDED"; - private Queue mAvailableTrafficChannelQueue = new ConcurrentLinkedQueue<>(); - private List mManagedTrafficChannels; + private Queue mAvailablePhase1TrafficChannelQueue = new ConcurrentLinkedQueue<>(); + private List mManagedPhase1TrafficChannels; + private Queue mAvailablePhase2TrafficChannelQueue = new ConcurrentLinkedQueue<>(); + private List mManagedPhase2TrafficChannels; + private Map mAllocatedTrafficChannelMap = new ConcurrentHashMap<>(); private Map mChannelGrantEventMap = new ConcurrentHashMap<>(); @@ -85,8 +104,11 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv private Listener mDecodeEventListener; private TrafficChannelTeardownMonitor mTrafficChannelTeardownMonitor = new TrafficChannelTeardownMonitor(); + private Channel mParentChannel; + private ScrambleParameters mPhase2ScrambleParameters; + private Listener mMessageListener; - private boolean mIgnoreDataCalls = false; + private boolean mIgnoreDataCalls; /** * Monitors call events and allocates traffic decoder channels in response @@ -97,42 +119,93 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv */ public P25TrafficChannelManager(Channel parentChannel) { - createTrafficChannels(parentChannel); - DecodeConfigP25Phase1 p25Config = (DecodeConfigP25Phase1)parentChannel.getDecodeConfiguration(); - mIgnoreDataCalls = p25Config.getIgnoreDataCalls(); + mParentChannel = parentChannel; + + if(parentChannel.getDecodeConfiguration() instanceof DecodeConfigP25Phase1) + { + mIgnoreDataCalls = ((DecodeConfigP25Phase1)parentChannel.getDecodeConfiguration()).getIgnoreDataCalls(); + } + + createPhase1TrafficChannels(); + createPhase2TrafficChannels(); } /** * Creates up to the maximum number of traffic channels for use in allocating traffic channels. * - * @param parentChannel for inheriting naming, alias list and traffic channel pool size properties + * Note: this method uses lazy initialization and will only create the channels once. Subsequent calls will be ignored. */ - private void createTrafficChannels(Channel parentChannel) + private void createPhase1TrafficChannels() { - DecodeConfiguration decodeConfiguration = parentChannel.getDecodeConfiguration(); - List trafficChannelList = new ArrayList<>(); - - if(decodeConfiguration instanceof DecodeConfigP25Phase1) + if(mManagedPhase1TrafficChannels == null) { - DecodeConfigP25Phase1 p25DecodeConfig = (DecodeConfigP25Phase1)decodeConfiguration; - - int maxTrafficChannels = p25DecodeConfig.getTrafficChannelPoolSize(); + DecodeConfiguration decodeConfiguration = mParentChannel.getDecodeConfiguration(); + List trafficChannelList = new ArrayList<>(); - for(int x = 0; x < maxTrafficChannels; x++) + if(decodeConfiguration instanceof DecodeConfigP25Phase1) { - Channel trafficChannel = new Channel("TRAFFIC", ChannelType.TRAFFIC); - trafficChannel.setAliasListName(parentChannel.getAliasListName()); - trafficChannel.setSystem(parentChannel.getSystem()); - trafficChannel.setSite(parentChannel.getSite()); - trafficChannel.setDecodeConfiguration(p25DecodeConfig); - trafficChannel.setEventLogConfiguration(parentChannel.getEventLogConfiguration()); - trafficChannel.setRecordConfiguration(parentChannel.getRecordConfiguration()); - trafficChannelList.add(trafficChannel); + DecodeConfigP25Phase1 p25DecodeConfig = (DecodeConfigP25Phase1)decodeConfiguration; + + int maxTrafficChannels = p25DecodeConfig.getTrafficChannelPoolSize(); + + if(maxTrafficChannels > 0) + { + for(int x = 0; x < maxTrafficChannels; x++) + { + Channel trafficChannel = new Channel("TRAFFIC", ChannelType.TRAFFIC); + trafficChannel.setAliasListName(mParentChannel.getAliasListName()); + trafficChannel.setSystem(mParentChannel.getSystem()); + trafficChannel.setSite(mParentChannel.getSite()); + trafficChannel.setDecodeConfiguration(p25DecodeConfig); + trafficChannel.setEventLogConfiguration(mParentChannel.getEventLogConfiguration()); + trafficChannel.setRecordConfiguration(mParentChannel.getRecordConfiguration()); + trafficChannelList.add(trafficChannel); + } + } } + + mAvailablePhase1TrafficChannelQueue.addAll(trafficChannelList); + mManagedPhase1TrafficChannels = Collections.unmodifiableList(trafficChannelList); } + } + + /** + * Creates up to the maximum number of traffic channels for use in allocating traffic channels. + * + * Note: this method uses lazy initialization and will only create the channels once. Subsequent calls will be ignored. + */ + private void createPhase2TrafficChannels() + { + if(mManagedPhase2TrafficChannels == null) + { + DecodeConfiguration decodeConfiguration = mParentChannel.getDecodeConfiguration(); + List trafficChannelList = new ArrayList<>(); + + if(decodeConfiguration instanceof DecodeConfigP25Phase1) + { + DecodeConfigP25Phase1 p25DecodeConfig = (DecodeConfigP25Phase1)decodeConfiguration; + + int maxTrafficChannels = p25DecodeConfig.getTrafficChannelPoolSize(); - mAvailableTrafficChannelQueue.addAll(trafficChannelList); - mManagedTrafficChannels = Collections.unmodifiableList(trafficChannelList); + if(maxTrafficChannels > 0) + { + for(int x = 0; x < maxTrafficChannels; x++) + { + Channel trafficChannel = new Channel("TRAFFIC", ChannelType.TRAFFIC); + trafficChannel.setAliasListName(mParentChannel.getAliasListName()); + trafficChannel.setSystem(mParentChannel.getSystem()); + trafficChannel.setSite(mParentChannel.getSite()); + trafficChannel.setDecodeConfiguration(new DecodeConfigP25Phase2()); + trafficChannel.setEventLogConfiguration(mParentChannel.getEventLogConfiguration()); + trafficChannel.setRecordConfiguration(mParentChannel.getRecordConfiguration()); + trafficChannelList.add(trafficChannel); + } + } + } + + mAvailablePhase2TrafficChannelQueue.addAll(trafficChannelList); + mManagedPhase2TrafficChannels = Collections.unmodifiableList(trafficChannelList); + } } /** @@ -158,8 +231,167 @@ public void broadcast(DecodeEvent decodeEvent) public void processChannelGrant(APCO25Channel apco25Channel, ServiceOptions serviceOptions, IdentifierCollection identifierCollection, Opcode opcode, long timestamp) { + if(apco25Channel.isTDMAChannel()) + { + if(apco25Channel.getTimeslotCount() == 2) + { + //Data channels may be granted as a phase 2 channel grant but are still phase 1 channels + if(opcode.isDataChannelGrant()) + { + APCO25Channel phase1Channel = convertPhase2ToPhase1(apco25Channel); + processPhase1ChannelGrant(phase1Channel, serviceOptions, identifierCollection, opcode, timestamp); + } + else + { + processPhase2ChannelGrant(apco25Channel, serviceOptions, identifierCollection, opcode, timestamp); + } + } + else + { + mLog.warn("Cannot process TDMA channel grant - unrecognized timeslot count: " + + apco25Channel.getTimeslotCount()); + } + } + else + { + processPhase1ChannelGrant(apco25Channel, serviceOptions, identifierCollection, opcode, timestamp); + } + } + + /** + * Processes Phase 1 channel grants to allocate traffic channels and track overall channel usage. Generates + * decode events for each new channel that is allocated. + * + * @param apco25Channel for the traffic channel + * @param serviceOptions for the traffic channel - optional can be null + * @param identifierCollection associated with the channel grant + * @param opcode to identify the call type for the event description + */ + private void processPhase1ChannelGrant(APCO25Channel apco25Channel, ServiceOptions serviceOptions, + IdentifierCollection identifierCollection, Opcode opcode, long timestamp) + { + + P25ChannelGrantEvent event = mChannelGrantEventMap.get(apco25Channel); + + if(event != null && isSameCall(identifierCollection, event.getIdentifierCollection())) + { + Identifier from = getIdentifier(identifierCollection, Role.FROM); + + if(from != null) + { + Identifier currentFrom = getIdentifier(event.getIdentifierCollection(), Role.FROM); + if(currentFrom != null && !Objects.equals(from, currentFrom)) + { + event.end(timestamp); + + P25ChannelGrantEvent continuationGrantEvent = P25ChannelGrantEvent.builder(timestamp, serviceOptions) + .channel(apco25Channel) + .eventDescription(getEventType(opcode, serviceOptions).toString() + " - Continue") + .details("CHANNEL GRANT " + (serviceOptions != null ? serviceOptions : "UNKNOWN SERVICE OPTIONS")) + .identifiers(identifierCollection) + .build(); + + mChannelGrantEventMap.put(apco25Channel, continuationGrantEvent); + broadcast(continuationGrantEvent); + } + } + + //update the ending timestamp so that the duration value is correctly calculated + event.update(timestamp); + broadcast(event); + + //Even though we have an event, the initial channel grant may have been rejected. Check to see if there + //is a traffic channel allocated. If not, allocate one and update the event description. + if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel) && !(mIgnoreDataCalls && opcode.isDataChannelGrant())) + { + Channel trafficChannel = mAvailablePhase1TrafficChannelQueue.poll(); + + if(trafficChannel != null) + { + event.setEventDescription(getEventType(opcode, serviceOptions).toString()); + event.setDetails("CHANNEL GRANT " + (serviceOptions != null ? serviceOptions : "UNKNOWN SERVICE OPTIONS")); + event.setChannelDescriptor(apco25Channel); + broadcast(event); + SourceConfigTuner sourceConfig = new SourceConfigTuner(); + sourceConfig.setFrequency(apco25Channel.getDownlinkFrequency()); + trafficChannel.setSourceConfiguration(sourceConfig); + mAllocatedTrafficChannelMap.put(apco25Channel, trafficChannel); + broadcast(new ChannelGrantEvent(trafficChannel, Event.REQUEST_ENABLE, apco25Channel, identifierCollection)); + } + } + + return; + } + + if(mIgnoreDataCalls && opcode.isDataChannelGrant()) + { + P25ChannelGrantEvent channelGrantEvent = P25ChannelGrantEvent.builder(timestamp, serviceOptions) + .channel(apco25Channel) + .eventDescription(getEventType(opcode, serviceOptions).toString() + " - Ignored") + .details("DATA CALL IGNORED: " + (serviceOptions != null ? serviceOptions : "UNKNOWN SERVICE OPTIONS")) + .identifiers(identifierCollection) + .build(); + + mChannelGrantEventMap.put(apco25Channel, channelGrantEvent); + + broadcast(channelGrantEvent); + return; + } + + P25ChannelGrantEvent channelGrantEvent = P25ChannelGrantEvent.builder(timestamp, serviceOptions) + .channel(apco25Channel) + .eventDescription(getEventType(opcode, serviceOptions).toString()) + .details("CHANNEL GRANT " + (serviceOptions != null ? serviceOptions : "UNKNOWN SERVICE OPTIONS")) + .identifiers(identifierCollection) + .build(); + + mChannelGrantEventMap.put(apco25Channel, channelGrantEvent); + + //Allocate a traffic channel for the downlink frequency if one isn't already allocated + //NOTE: we could also allocate a traffic channel for the uplink frequency here, in the future + if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel)) + { + Channel trafficChannel = mAvailablePhase1TrafficChannelQueue.poll(); + + if(trafficChannel == null) + { + channelGrantEvent.setDetails(MAX_TRAFFIC_CHANNELS_EXCEEDED); + channelGrantEvent.setEventDescription(channelGrantEvent.getEventDescription() + " - Ignored"); + return; + } + + SourceConfigTuner sourceConfig = new SourceConfigTuner(); + sourceConfig.setFrequency(apco25Channel.getDownlinkFrequency()); + trafficChannel.setSourceConfiguration(sourceConfig); + mAllocatedTrafficChannelMap.put(apco25Channel, trafficChannel); + broadcast(new ChannelGrantEvent(trafficChannel, Event.REQUEST_ENABLE, apco25Channel, identifierCollection)); + } + + broadcast(channelGrantEvent); + } + + + /** + * Processes Phase 2 channel grants to allocate traffic channels and track overall channel usage. Generates + * decode events for each new channel that is allocated. + * + * @param apco25Channel for the traffic channel + * @param serviceOptions for the traffic channel - optional can be null + * @param identifierCollection associated with the channel grant + * @param opcode to identify the call type for the event description + */ + private void processPhase2ChannelGrant(APCO25Channel apco25Channel, ServiceOptions serviceOptions, + IdentifierCollection identifierCollection, Opcode opcode, long timestamp) + { + if(mPhase2ScrambleParameters != null && identifierCollection instanceof MutableIdentifierCollection) + { + ((MutableIdentifierCollection)identifierCollection).silentUpdate(ScrambleParameterIdentifier.create(mPhase2ScrambleParameters)); + } + P25ChannelGrantEvent event = mChannelGrantEventMap.get(apco25Channel); + identifierCollection.setTimeslot(apco25Channel.getTimeslot()); + if(event != null && isSameCall(identifierCollection, event.getIdentifierCollection())) { Identifier from = getIdentifier(identifierCollection, Role.FROM); @@ -190,9 +422,9 @@ public void processChannelGrant(APCO25Channel apco25Channel, ServiceOptions serv //Even though we have an event, the initial channel grant may have been rejected. Check to see if there //is a traffic channel allocated. If not, allocate one and update the event description. if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel) && - !(mIgnoreDataCalls && opcode == Opcode.OSP_SNDCP_DATA_CHANNEL_GRANT)) + !(mIgnoreDataCalls && opcode.isDataChannelGrant())) { - Channel trafficChannel = mAvailableTrafficChannelQueue.poll(); + Channel trafficChannel = mAvailablePhase2TrafficChannelQueue.poll(); if(trafficChannel != null) { @@ -204,6 +436,14 @@ public void processChannelGrant(APCO25Channel apco25Channel, ServiceOptions serv sourceConfig.setFrequency(apco25Channel.getDownlinkFrequency()); trafficChannel.setSourceConfiguration(sourceConfig); mAllocatedTrafficChannelMap.put(apco25Channel, trafficChannel); + + //If we have valid scramble/randomizer parameters, set them in the decode config + if(mPhase2ScrambleParameters != null) + { + DecodeConfigP25Phase2 decodeConfig = (DecodeConfigP25Phase2)trafficChannel.getDecodeConfiguration(); + decodeConfig.setScrambleParameters(mPhase2ScrambleParameters.copy()); + } + broadcast(new ChannelGrantEvent(trafficChannel, Event.REQUEST_ENABLE, apco25Channel, identifierCollection)); } } @@ -211,7 +451,7 @@ public void processChannelGrant(APCO25Channel apco25Channel, ServiceOptions serv return; } - if(mIgnoreDataCalls && opcode == Opcode.OSP_SNDCP_DATA_CHANNEL_GRANT) + if(mIgnoreDataCalls && opcode.isDataChannelGrant()) { P25ChannelGrantEvent channelGrantEvent = P25ChannelGrantEvent.builder(timestamp, serviceOptions) .channel(apco25Channel) @@ -239,7 +479,7 @@ public void processChannelGrant(APCO25Channel apco25Channel, ServiceOptions serv //NOTE: we could also allocate a traffic channel for the uplink frequency here, in the future if(!mAllocatedTrafficChannelMap.containsKey(apco25Channel)) { - Channel trafficChannel = mAvailableTrafficChannelQueue.poll(); + Channel trafficChannel = mAvailablePhase2TrafficChannelQueue.poll(); if(trafficChannel == null) { @@ -382,14 +622,10 @@ private Identifier getIdentifier(IdentifierCollection collection, Role role) @Override public void dispose() { - for(Channel trafficChannel : mAvailableTrafficChannelQueue) + for(Channel trafficChannel : mAvailablePhase1TrafficChannelQueue) { broadcast(new ChannelEvent(trafficChannel, Event.REQUEST_DISABLE)); } - - mAvailableTrafficChannelQueue.clear(); - -// mTrafficChannelsInUse.clear(); } /** @@ -433,6 +669,66 @@ public void stop() } } + /** + * Processes the decoded message stream and captures P25 Phase II randomizer (scramble) parameters from the TSBK + * network status broadcast message so that we can pre-load any Phase2 channels with the correct descrambler + * sequence. + * + * @return listener to process the message stream. + */ + @Override + public Listener getMessageListener() + { + if(mMessageListener == null) + { + mMessageListener = new Listener() + { + @Override + public void receive(IMessage message) + { + if(mPhase2ScrambleParameters == null && message.isValid()) + { + if(message instanceof NetworkStatusBroadcast) + { + mPhase2ScrambleParameters = ((NetworkStatusBroadcast)message).getScrambleParameters(); + } + else if(message instanceof AMBTCNetworkStatusBroadcast) + { + mPhase2ScrambleParameters = ((AMBTCNetworkStatusBroadcast)message).getScrambleParameters(); + } + } + } + }; + } + + return mMessageListener; + } + + /** + * Converts a phase 2 channel to a phase 1 channel + * @param channel to convert + * @return channel converted to phase 1 or the original channel if no conversion is necessary + */ + private static APCO25Channel convertPhase2ToPhase1(APCO25Channel channel) + { + P25Channel toConvert = channel.getValue(); + + if(toConvert instanceof P25P2ExplicitChannel) + { + P25P2ExplicitChannel phase2 = (P25P2ExplicitChannel)toConvert; + return APCO25ExplicitChannel.create(phase2.getDownlinkBandIdentifier(), + phase2.getDownlinkChannelNumber(), phase2.getUplinkBandIdentifier(), + phase2.getUplinkChannelNumber()); + } + else if(toConvert instanceof P25P2Channel) + { + P25P2Channel phase2 = (P25P2Channel)toConvert; + return APCO25Channel.create(phase2.getDownlinkBandIdentifier(), phase2.getDownlinkChannelNumber()); + } + + return channel; + } + /** * Monitors channel teardown events to detect when traffic channel processing has ended. Reclaims the * channel instance for reuse by future traffic channel grants. @@ -444,70 +740,94 @@ public synchronized void receive(ChannelEvent channelEvent) { Channel channel = channelEvent.getChannel(); - if(channel.isTrafficChannel() && mManagedTrafficChannels.contains(channel)) + if(channel.isTrafficChannel()) { - switch(channelEvent.getEvent()) + boolean isPhase1 = channel.getDecodeConfiguration().getDecoderType() == DecoderType.P25_PHASE1; + + if((isPhase1 && mManagedPhase1TrafficChannels.contains(channel)) || + (!isPhase1 && mManagedPhase2TrafficChannels.contains(channel))) { - case NOTIFICATION_PROCESSING_STOP: - APCO25Channel toRemove = null; + switch(channelEvent.getEvent()) + { + case NOTIFICATION_PROCESSING_STOP: + APCO25Channel toRemove = null; - for(Map.Entry entry: mAllocatedTrafficChannelMap.entrySet()) - { - if(entry.getValue() == channel) + for(Map.Entry entry: mAllocatedTrafficChannelMap.entrySet()) { - toRemove = entry.getKey(); - continue; + if(entry.getValue() == channel) + { + toRemove = entry.getKey(); + continue; + } } - } - if(toRemove != null) - { - mAllocatedTrafficChannelMap.remove(toRemove); - mAvailableTrafficChannelQueue.add(channel); - P25ChannelGrantEvent event = mChannelGrantEventMap.remove(toRemove); - - if(event != null) + if(toRemove != null) { - event.end(System.currentTimeMillis()); - broadcast(event); + mAllocatedTrafficChannelMap.remove(toRemove); + + if(isPhase1) + { + mAvailablePhase1TrafficChannelQueue.add(channel); + } + else + { + mAvailablePhase2TrafficChannelQueue.add(channel); + } + + P25ChannelGrantEvent event = mChannelGrantEventMap.remove(toRemove); + + if(event != null) + { + event.end(System.currentTimeMillis()); + broadcast(event); + } } - } - break; - case NOTIFICATION_PROCESSING_START_REJECTED: - APCO25Channel rejected = null; + break; + case NOTIFICATION_PROCESSING_START_REJECTED: + APCO25Channel rejected = null; - for(Map.Entry entry: mAllocatedTrafficChannelMap.entrySet()) - { - if(entry.getValue() == channel) + for(Map.Entry entry: mAllocatedTrafficChannelMap.entrySet()) { - rejected = entry.getKey(); - continue; + if(entry.getValue() == channel) + { + rejected = entry.getKey(); + continue; + } } - } - if(rejected != null) - { - mAllocatedTrafficChannelMap.remove(rejected); - mAvailableTrafficChannelQueue.add(channel); - P25ChannelGrantEvent event = mChannelGrantEventMap.get(rejected); - - if(event != null) + if(rejected != null) { - event.setEventDescription(event.getEventDescription() + " - Rejected"); + mAllocatedTrafficChannelMap.remove(rejected); - if(channelEvent.getDescription() != null) + if(isPhase1) { - event.setDetails(channelEvent.getDescription() + " - " + event.getDetails()); + mAvailablePhase1TrafficChannelQueue.add(channel); } else { - event.setDetails(CHANNEL_START_REJECTED + " - " + event.getDetails()); + mAvailablePhase2TrafficChannelQueue.add(channel); } - broadcast(event); + P25ChannelGrantEvent event = mChannelGrantEventMap.get(rejected); + + if(event != null) + { + event.setEventDescription(event.getEventDescription() + " - Rejected"); + + if(channelEvent.getDescription() != null) + { + event.setDetails(channelEvent.getDescription() + " - " + event.getDetails()); + } + else + { + event.setDetails(CHANNEL_START_REJECTED + " - " + event.getDetails()); + } + + broadcast(event); + } } - } - break; + break; + } } } } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25AudioModule.java b/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25AudioModule.java deleted file mode 100644 index 48be471c5..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25AudioModule.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * ****************************************************************************** - * sdrtrunk - * 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 - * ***************************************************************************** - */ -package io.github.dsheirer.module.decode.p25.audio; - -import com.google.common.eventbus.Subscribe; -import io.github.dsheirer.audio.AbstractAudioModule; -import io.github.dsheirer.audio.AudioFormats; -import io.github.dsheirer.audio.squelch.SquelchState; -import io.github.dsheirer.dsp.gain.NonClippingGain; -import io.github.dsheirer.eventbus.MyEventBus; -import io.github.dsheirer.message.IMessage; -import io.github.dsheirer.message.IMessageListener; -import io.github.dsheirer.module.decode.p25.message.hdu.HDUMessage; -import io.github.dsheirer.module.decode.p25.message.ldu.LDU1Message; -import io.github.dsheirer.module.decode.p25.message.ldu.LDU2Message; -import io.github.dsheirer.module.decode.p25.message.ldu.LDUMessage; -import io.github.dsheirer.preference.PreferenceType; -import io.github.dsheirer.preference.UserPreferences; -import io.github.dsheirer.sample.Listener; -import io.github.dsheirer.sample.buffer.ReusableAudioPacket; -import io.github.dsheirer.sample.buffer.ReusableAudioPacketQueue; -import jmbe.iface.AudioConversionLibrary; -import jmbe.iface.AudioConverter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Path; - -public class P25AudioModule extends AbstractAudioModule implements Listener, IMessageListener -{ - private static final Logger mLog = LoggerFactory.getLogger(P25AudioModule.class); - private static final String IMBE_CODEC = "IMBE"; - private static boolean mLibraryLoadStatusLogged = false; - - private boolean mCanConvertAudio = false; - private boolean mEncryptedCall = false; - private boolean mEncryptedCallStateEstablished = false; - - private AudioConverter mAudioConverter; - private SquelchStateListener mSquelchStateListener = new SquelchStateListener(); - private NonClippingGain mGain = new NonClippingGain(5.0f, 0.95f); - private LDU1Message mCachedLDU1Message = null; - private ReusableAudioPacketQueue mAudioPacketQueue = new ReusableAudioPacketQueue("P25AudioModule"); - private UserPreferences mUserPreferences; - - public P25AudioModule(UserPreferences userPreferences) - { - mUserPreferences = userPreferences; - MyEventBus.getEventBus().register(this); - loadConverter(); - } - - @Override - public Listener getMessageListener() - { - return this; - } - - @Override - public Listener getSquelchStateListener() - { - return mSquelchStateListener; - } - - @Override - public void dispose() - { - mAudioConverter = null; - } - - @Override - public void reset() - { - getIdentifierCollection().clear(); - } - - @Override - public void start() - { - - } - - @Override - public void stop() - { - if(hasAudioPacketListener()) - { - ReusableAudioPacket endAudioPacket = mAudioPacketQueue.getEndAudioBuffer(); - endAudioPacket.resetAttributes(); - endAudioPacket.setAudioChannelId(getAudioChannelId()); - endAudioPacket.setIdentifierCollection(getIdentifierCollection().copyOf()); - endAudioPacket.incrementUserCount(); - getAudioPacketListener().receive(endAudioPacket); - } - } - - /** - * Processes call header (HDU) and voice frame (LDU1/LDU2) messages to decode audio and to determine the - * encrypted audio status of a call event. Only the HDU and LDU2 messages convey encrypted call status. If an - * LDU1 message is received without a preceding HDU message, then the LDU1 message is cached until the first - * LDU2 message is received and the encryption state can be determined. Both the LDU1 and the LDU2 message are - * then processed for audio if the call is unencrypted. - */ - public void receive(IMessage message) - { - if(mCanConvertAudio && hasAudioPacketListener()) - { - if(mEncryptedCallStateEstablished) - { - if(message instanceof LDUMessage) - { - processAudio((LDUMessage)message); - } - } - else - { - if(message instanceof HDUMessage) - { - mEncryptedCallStateEstablished = true; - mEncryptedCall = ((HDUMessage)message).getHeaderData().isEncryptedAudio(); - } - else if(message instanceof LDU1Message) - { - //When we receive an LDU1 message without first receiving the HDU message, cache the LDU1 Message - //until we can determine the encrypted call state from the next LDU2 message - mCachedLDU1Message = (LDU1Message)message; - } - else if(message instanceof LDU2Message) - { - mEncryptedCallStateEstablished = true; - LDU2Message ldu2 = (LDU2Message)message; - mEncryptedCall = ldu2.getEncryptionSyncParameters().isEncryptedAudio(); - - if(mCachedLDU1Message != null) - { - processAudio(mCachedLDU1Message); - mCachedLDU1Message = null; - } - - processAudio(ldu2); - } - } - } - } - - /** - * Processes an audio packet by decoding the IMBE audio frames and rebroadcasting them as PCM audio packets. - */ - private void processAudio(LDUMessage ldu) - { - if(!mEncryptedCall) - { - for(byte[] frame : ldu.getIMBEFrames()) - { - float[] audio = mAudioConverter.decode(frame); - - audio = mGain.apply(audio); - - ReusableAudioPacket audioPacket = mAudioPacketQueue.getBuffer(audio.length); - audioPacket.resetAttributes(); - audioPacket.setAudioChannelId(getAudioChannelId()); - audioPacket.setIdentifierCollection(getIdentifierCollection().copyOf()); - audioPacket.loadAudioFrom(audio); - - getAudioPacketListener().receive(audioPacket); - } - } - else - { - //Encrypted audio processing not implemented - } - } - - /** - * Receives notifications that the JMBE library preference has been updated via the Guava event bus - * - * @param preferenceType that was updated - */ - @Subscribe - public void preferenceUpdated(PreferenceType preferenceType) - { - if(preferenceType == PreferenceType.JMBE_LIBRARY) - { - mLibraryLoadStatusLogged = false; - loadConverter(); - } - } - - /** - * Loads audio frame processing chain. Constructs an imbe targetdataline - * to receive the raw imbe frames. Adds an IMBE to 8k PCM format conversion - * stream wrapper. Finally, adds an upsampling (8k to 48k) stream wrapper. - */ - private void loadConverter() - { - AudioConverter audioConverter = null; - - Path path = mUserPreferences.getJmbeLibraryPreference().getPathJmbeLibrary(); - - if(path != null) - { - try - { - if(!mLibraryLoadStatusLogged) - { - mLog.info("Loading JMBE library from [" + path.toString() + "]"); - } - - URLClassLoader childClassLoader = new URLClassLoader(new URL[]{path.toUri().toURL()}, - this.getClass().getClassLoader()); - - Class classToLoad = Class.forName("jmbe.JMBEAudioLibrary", true, childClassLoader); - - Object instance = classToLoad.getDeclaredConstructor().newInstance(); - - if(instance instanceof AudioConversionLibrary) - { - AudioConversionLibrary library = (AudioConversionLibrary)instance; - - if((library.getMajorVersion() == 0 && library.getMinorVersion() >= 3 && - library.getBuildVersion() >= 3) || library.getMajorVersion() >= 1) - { - audioConverter = library.getAudioConverter(IMBE_CODEC, AudioFormats.PCM_SIGNED_8KHZ_16BITS_MONO); - } - else - { - mLog.warn("JMBE library version 0.3.3 or higher is required - found: " + library.getVersion()); - } - } - else - { - if(!mLibraryLoadStatusLogged) - { - mLog.info("JMBE audio conversion library NOT FOUND"); - mLibraryLoadStatusLogged = true; - } - } - } - catch(NoSuchMethodException nsme) - { - if(!mLibraryLoadStatusLogged) - { - mLog.error("Couldn't load JMBE audio conversion library - no such method exception"); - mLibraryLoadStatusLogged = true; - } - } - catch(MalformedURLException mue) - { - if(!mLibraryLoadStatusLogged) - { - mLog.error("Couldn't load JMBE audio conversion library from path [" + path + "]"); - mLibraryLoadStatusLogged = true; - } - } - catch(ClassNotFoundException e1) - { - if(!mLibraryLoadStatusLogged) - { - mLog.error("Couldn't load JMBE audio conversion library - class not found"); - mLibraryLoadStatusLogged = true; - } - } - catch(InvocationTargetException ite) - { - if(!mLibraryLoadStatusLogged) - { - mLog.error("Couldn't load JMBE audio conversion library - invocation target exception", ite); - mLibraryLoadStatusLogged = true; - } - } - catch(InstantiationException e1) - { - if(!mLibraryLoadStatusLogged) - { - mLog.error("Couldn't load JMBE audio conversion library - instantiation exception", e1); - mLibraryLoadStatusLogged = true; - } - } - catch(IllegalAccessException e1) - { - if(!mLibraryLoadStatusLogged) - { - mLog.error("Couldn't load JMBE audio conversion library - security restrictions"); - mLibraryLoadStatusLogged = true; - } - } - } - else - { - mLog.info("JMBE audio library path is NOT SET in your User Preferences."); - } - - if(audioConverter != null) - { - mAudioConverter = audioConverter; - mCanConvertAudio = true; - - if(!mLibraryLoadStatusLogged) - { - mLog.info("JMBE audio conversion library successfully loaded - P25 audio will be available"); - mLibraryLoadStatusLogged = true; - } - } - else - { - mCanConvertAudio = false; - mAudioConverter = null; - - if(!mLibraryLoadStatusLogged) - { - mLog.info("JMBE audio conversion library NOT FOUND"); - mLibraryLoadStatusLogged = true; - } - } - } - - /** - * Wrapper for squelch state to process end of call actions. At call end the encrypted call state established - * flag is reset so that the encrypted audio state for the next call can be properly detected and we send an - * END audio packet so that downstream processors like the audio recorder can properly close out a call sequence. - */ - public class SquelchStateListener implements Listener - { - @Override - public void receive(SquelchState state) - { - if(state == SquelchState.SQUELCH) - { - if(hasAudioPacketListener()) - { - ReusableAudioPacket endAudioPacket = mAudioPacketQueue.getEndAudioBuffer(); - endAudioPacket.resetAttributes(); - endAudioPacket.setAudioChannelId(getAudioChannelId()); - endAudioPacket.setIdentifierCollection(getIdentifierCollection().copyOf()); - endAudioPacket.incrementUserCount(); - getAudioPacketListener().receive(endAudioPacket); - } - - mEncryptedCallStateEstablished = false; - mEncryptedCall = false; - mCachedLDU1Message = null; - } - } - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25P1AudioModule.java b/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25P1AudioModule.java new file mode 100644 index 000000000..d7291aa74 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25P1AudioModule.java @@ -0,0 +1,188 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.audio; + +import io.github.dsheirer.audio.codec.mbe.ImbeAudioModule; +import io.github.dsheirer.audio.squelch.SquelchState; +import io.github.dsheirer.audio.squelch.SquelchStateEvent; +import io.github.dsheirer.dsp.gain.NonClippingGain; +import io.github.dsheirer.message.IMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.hdu.HDUMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU1Message; +import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU2Message; +import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDUMessage; +import io.github.dsheirer.preference.UserPreferences; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableAudioPacket; + +public class P25P1AudioModule extends ImbeAudioModule +{ + private boolean mEncryptedCall = false; + private boolean mEncryptedCallStateEstablished = false; + + private SquelchStateListener mSquelchStateListener = new SquelchStateListener(); + private NonClippingGain mGain = new NonClippingGain(5.0f, 0.95f); + private LDU1Message mCachedLDU1Message = null; + + public P25P1AudioModule(UserPreferences userPreferences) + { + super(userPreferences); + } + + @Override + public Listener getSquelchStateListener() + { + return mSquelchStateListener; + } + + @Override + public void reset() + { + getIdentifierCollection().clear(); + } + + @Override + public void start() + { + + } + + @Override + public void stop() + { + if(hasAudioPacketListener()) + { + ReusableAudioPacket endAudioPacket = getAudioPacketQueue().getEndAudioBuffer(); + endAudioPacket.resetAttributes(); + endAudioPacket.setAudioChannelId(getAudioChannelId()); + endAudioPacket.setIdentifierCollection(getIdentifierCollection().copyOf()); + endAudioPacket.incrementUserCount(); + getAudioPacketListener().receive(endAudioPacket); + } + } + + /** + * Processes call header (HDU) and voice frame (LDU1/LDU2) messages to decode audio and to determine the + * encrypted audio status of a call event. Only the HDU and LDU2 messages convey encrypted call status. If an + * LDU1 message is received without a preceding HDU message, then the LDU1 message is cached until the first + * LDU2 message is received and the encryption state can be determined. Both the LDU1 and the LDU2 message are + * then processed for audio if the call is unencrypted. + */ + public void receive(IMessage message) + { + if(hasAudioCodec() && hasAudioPacketListener()) + { + if(mEncryptedCallStateEstablished) + { + if(message instanceof LDUMessage) + { + processAudio((LDUMessage)message); + } + } + else + { + if(message instanceof HDUMessage) + { + mEncryptedCallStateEstablished = true; + mEncryptedCall = ((HDUMessage)message).getHeaderData().isEncryptedAudio(); + } + else if(message instanceof LDU1Message) + { + //When we receive an LDU1 message without first receiving the HDU message, cache the LDU1 Message + //until we can determine the encrypted call state from the next LDU2 message + mCachedLDU1Message = (LDU1Message)message; + } + else if(message instanceof LDU2Message) + { + mEncryptedCallStateEstablished = true; + LDU2Message ldu2 = (LDU2Message)message; + mEncryptedCall = ldu2.getEncryptionSyncParameters().isEncryptedAudio(); + + if(mCachedLDU1Message != null) + { + processAudio(mCachedLDU1Message); + mCachedLDU1Message = null; + } + + processAudio(ldu2); + } + } + } + } + + /** + * Processes an audio packet by decoding the IMBE audio frames and rebroadcasting them as PCM audio packets. + */ + private void processAudio(LDUMessage ldu) + { + if(!mEncryptedCall) + { + for(byte[] frame : ldu.getIMBEFrames()) + { + float[] audio = getAudioCodec().getAudio(frame); + + audio = mGain.apply(audio); + + ReusableAudioPacket audioPacket = getAudioPacketQueue().getBuffer(audio.length); + audioPacket.resetAttributes(); + audioPacket.setAudioChannelId(getAudioChannelId()); + audioPacket.setIdentifierCollection(getIdentifierCollection().copyOf()); + audioPacket.loadAudioFrom(audio); + + getAudioPacketListener().receive(audioPacket); + } + } + else + { + //Encrypted audio processing not implemented + } + } + + /** + * Wrapper for squelch state to process end of call actions. At call end the encrypted call state established + * flag is reset so that the encrypted audio state for the next call can be properly detected and we send an + * END audio packet so that downstream processors like the audio recorder can properly close out a call sequence. + */ + public class SquelchStateListener implements Listener + { + @Override + public void receive(SquelchStateEvent event) + { + if(event.getSquelchState() == SquelchState.SQUELCH) + { + if(hasAudioPacketListener()) + { + ReusableAudioPacket endAudioPacket = getAudioPacketQueue().getEndAudioBuffer(); + endAudioPacket.resetAttributes(); + endAudioPacket.setAudioChannelId(getAudioChannelId()); + endAudioPacket.setIdentifierCollection(getIdentifierCollection().copyOf()); + endAudioPacket.incrementUserCount(); + getAudioPacketListener().receive(endAudioPacket); + } + + mEncryptedCallStateEstablished = false; + mEncryptedCall = false; + mCachedLDU1Message = null; + } + } + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25P1CallSequenceRecorder.java b/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25P1CallSequenceRecorder.java new file mode 100644 index 000000000..1eda09d0e --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25P1CallSequenceRecorder.java @@ -0,0 +1,235 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +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.message.IMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.P25Message; +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.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; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCUnitToUnitVoiceChannelUser; +import io.github.dsheirer.module.decode.p25.phase1.message.ldu.EncryptionSyncParameters; +import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU1Message; +import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU2Message; +import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDUMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDULinkControlMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDUMessage; +import io.github.dsheirer.preference.UserPreferences; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * P25 Phase 1 IMBE Frame recorder generates P25 call sequence recordings containing JSON representations of audio + * frames, optional encryption and call identifiers. + */ +public class P25P1CallSequenceRecorder extends MBECallSequenceRecorder +{ + private final static Logger mLog = LoggerFactory.getLogger(P25P1CallSequenceRecorder.class); + + private static final String PROTOCOL = "APCO25-PHASE1"; + + private MBECallSequence mCallSequence; + + /** + * Constructs a P25-Phase2 MBE call sequence recorder. + * + * @param userPreferences to obtain the recording directory + * @param channelFrequency for the channel to record + * @param system defined by the user + * @param site defined by the user + */ + public P25P1CallSequenceRecorder(UserPreferences userPreferences, long channelFrequency, String system, String site) + { + super(userPreferences, channelFrequency, system, site); + } + + /** + * Stops and flushes any partial frame sequence from the processors + */ + @Override + public void stop() + { + flush(); + } + + /** + * Primary message interface for receiving frames and metadata messages to record + */ + @Override + public void receive(IMessage message) + { + if(message instanceof P25Message) + { + P25Message p25 = (P25Message)message; + + if(p25.isValid()) + { + process(p25); + } + } + } + + + /** + * Flushes any partial call sequence + */ + public void flush() + { + if(mCallSequence != null) + { + writeCallSequence(mCallSequence); + mCallSequence = null; + } + } + + /** + * Processes any P25 Phase 1 message + */ + public void process(P25Message message) + { + if(message instanceof LDUMessage) + { + process((LDUMessage)message); + } + else if(message instanceof TDULinkControlMessage) + { + process((TDULinkControlMessage)message); + } + else if(message instanceof TDUMessage) + { + flush(); + } + } + + private void process(TDULinkControlMessage tdulc) + { + process(tdulc.getLinkControlWord()); + } + + /** + * Processes Voice LDU messages + */ + private void process(LDUMessage lduMessage) + { + if(mCallSequence == null) + { + mCallSequence = new MBECallSequence(PROTOCOL); + } + + if(lduMessage instanceof LDU1Message) + { + process((LDU1Message)lduMessage); + } + else if(lduMessage instanceof LDU2Message) + { + process((LDU2Message)lduMessage); + } + + List voiceFrames = lduMessage.getIMBEFrames(); + + long baseTimestamp = lduMessage.getTimestamp(); + + for(byte[] frame : voiceFrames) + { + BinaryMessage frameBits = BinaryMessage.from(frame); + mCallSequence.addVoiceFrame(baseTimestamp, frameBits.toHexString()); + + //Voice frames are 20 milliseconds each, so we increment the timestamp by 20 for each one + baseTimestamp += 20; + } + + } + + private void process(LinkControlWord lcw) + { + if(lcw.isValid() && mCallSequence != null) + { + switch(lcw.getOpcode()) + { + case GROUP_VOICE_CHANNEL_USER: + LCGroupVoiceChannelUser gvcu = (LCGroupVoiceChannelUser)lcw; + mCallSequence.setFromIdentifier(gvcu.getSourceAddress().toString()); + mCallSequence.setToIdentifier(gvcu.getGroupAddress().toString()); + mCallSequence.setCallType(CALL_TYPE_GROUP); + break; + case UNIT_TO_UNIT_VOICE_CHANNEL_USER: + LCUnitToUnitVoiceChannelUser uuvcu = (LCUnitToUnitVoiceChannelUser)lcw; + mCallSequence.setFromIdentifier(uuvcu.getSourceAddress().toString()); + mCallSequence.setToIdentifier(uuvcu.getTargetAddress().toString()); + mCallSequence.setCallType(CALL_TYPE_INDIVIDUAL); + break; + case GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT: + LCGroupVoiceChannelUpdateExplicit gvcue = (LCGroupVoiceChannelUpdateExplicit)lcw; + mCallSequence.setToIdentifier(gvcue.getGroupAddress().toString()); + mCallSequence.setCallType(CALL_TYPE_GROUP); + break; + case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER: + LCTelephoneInterconnectVoiceChannelUser tivcu = (LCTelephoneInterconnectVoiceChannelUser)lcw; + mCallSequence.setToIdentifier(tivcu.getAddress().toString()); + mCallSequence.setCallType(CALL_TYPE_TELEPHONE_INTERCONNECT); + break; + case MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_USER: + LCMotorolaPatchGroupVoiceChannelUser mpgvcu = (LCMotorolaPatchGroupVoiceChannelUser)lcw; + mCallSequence.setFromIdentifier(mpgvcu.getSourceAddress().toString()); + mCallSequence.setToIdentifier(mpgvcu.getGroupAddress().toString()); + mCallSequence.setCallType(CALL_TYPE_GROUP); + break; + case MOTOROLA_PATCH_GROUP_VOICE_CHANNEL_UPDATE: + LCMotorolaPatchGroupVoiceChannelUpdate mpgvcup = (LCMotorolaPatchGroupVoiceChannelUpdate)lcw; + mCallSequence.setToIdentifier(mpgvcup.getPatchGroup().toString()); + mCallSequence.setCallType(CALL_TYPE_GROUP); + break; + case CALL_TERMINATION_OR_CANCELLATION: + case MOTOROLA_TALK_COMPLETE: + writeCallSequence(mCallSequence); + mCallSequence = null; + break; + } + } + } + + private void process(LDU1Message ldu1Message) + { + process(ldu1Message.getLinkControlWord()); + } + + private void process(LDU2Message ldu2Message) + { + EncryptionSyncParameters parameters = ldu2Message.getEncryptionSyncParameters(); + + if(parameters.isValid() && parameters.isEncryptedAudio()) + { + mCallSequence.setEncrypted(true); + mCallSequence.setEncryptionSyncParameters(parameters); + } + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25P2AudioModule.java b/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25P2AudioModule.java new file mode 100644 index 000000000..a55efe32f --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25P2AudioModule.java @@ -0,0 +1,375 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.audio; + +import io.github.dsheirer.audio.codec.mbe.AmbeAudioModule; +import io.github.dsheirer.audio.squelch.SquelchState; +import io.github.dsheirer.audio.squelch.SquelchStateEvent; +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.IdentifierUpdateNotification; +import io.github.dsheirer.identifier.IdentifierUpdateProvider; +import io.github.dsheirer.identifier.tone.P25CallProgressIdentifier; +import io.github.dsheirer.identifier.tone.P25DtmfIdentifier; +import io.github.dsheirer.identifier.tone.P25KnoxIdentifier; +import io.github.dsheirer.identifier.tone.P25ToneIdentifier; +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.mac.structure.PushToTalk; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.AbstractVoiceTimeslot; +import io.github.dsheirer.preference.UserPreferences; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableAudioPacket; +import jmbe.iface.IAudioWithMetadata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Queue; + +public class P25P2AudioModule extends AmbeAudioModule implements IdentifierUpdateProvider +{ + private final static Logger mLog = LoggerFactory.getLogger(P25P2AudioModule.class); + + private static final String METADATA_TYPE_DTMF = "DTMF"; + private static final String METADATA_TYPE_KNOX = "KNOX"; + private static final String METADATA_TYPE_TONE = "TONE"; + private static final String METADATA_TYPE_CALL_PROGRESS = "CALL PROGRESS"; + + private Listener mIdentifierUpdateNotificationListener; + private MetadataProcessor mDtmfMetadataProcessor; + private MetadataProcessor mKnoxMetadataProcessor; + private MetadataProcessor mToneMetadataProcessor; + private MetadataProcessor mCallProcessMetadataProcessor; + private int mTimeslot; + private Queue mQueuedAudioTimeslots = new ArrayDeque<>(); + private boolean mEncryptedCallStateEstablished = false; + private boolean mEncryptedCall = false; + + public P25P2AudioModule(UserPreferences userPreferences, int timeslot) + { + super(userPreferences); + mTimeslot = timeslot; + getIdentifierCollection().setTimeslot(timeslot); + } + + private int getTimeslot() + { + return mTimeslot; + } + + @Override + public Listener getSquelchStateListener() + { + return null; + } + + @Override + public void reset() + { + mCallProcessMetadataProcessor = null; + mDtmfMetadataProcessor = null; + mKnoxMetadataProcessor = null; + mToneMetadataProcessor = null; + mQueuedAudioTimeslots.clear(); + } + + @Override + public void start() + { + reset(); + } + + @Override + public void stop() + { + + } + + /** + * Primary message processing method for processing voice timeslots and Push-To-Talk MAC messages + * + * Audio timeslots are temporarily queued until a determination of the encrypted state of the call is determined + * and then all queued audio is processed through to the end of the call. Encryption state is determined either + * by the PTT MAC message or by processing the ESS fragments from the Voice2 and Voice4 timeslots. + * + * @param message to process + */ + @Override + public void receive(IMessage message) + { + if(message.getTimeslot() == getTimeslot()) + { + if(message instanceof AbstractVoiceTimeslot) + { + AbstractVoiceTimeslot abstractVoiceTimeslot = (AbstractVoiceTimeslot)message; + + if(mEncryptedCallStateEstablished) + { + if(!mEncryptedCall) + { + processAudio(abstractVoiceTimeslot.getVoiceFrames()); + } + } + else + { + //Queue audio timeslots until we can determine if the audio is encrypted or not + mQueuedAudioTimeslots.offer(abstractVoiceTimeslot); + } + } + else if(message instanceof PushToTalk && message.isValid()) + { + mEncryptedCallStateEstablished = true; + mEncryptedCall = ((PushToTalk)message).isEncrypted(); + + //There should not be any pending voice timeslots to process since the PTT message is the first in + //the audio call sequence + } + else if(message instanceof EncryptionSynchronizationSequence) + { + mEncryptedCallStateEstablished = true; + mEncryptedCall = ((EncryptionSynchronizationSequence)message).isEncrypted(); + processPendingVoiceTimeslots(); + } + } + } + + /** + * Drains and processes any audio timeslots that have been queued pending determination of encrypted call status + */ + private void processPendingVoiceTimeslots() + { + AbstractVoiceTimeslot timeslot = mQueuedAudioTimeslots.poll(); + + while(timeslot != null) + { + receive(timeslot); + timeslot = mQueuedAudioTimeslots.poll(); + } + } + + private void processAudio(List voiceFrames) + { + if(hasAudioCodec() && hasAudioPacketListener()) + { + for(BinaryMessage voiceFrame: voiceFrames) + { + byte[] voiceFrameBytes = voiceFrame.getBytes(); + + IAudioWithMetadata audioWithMetadata = getAudioCodec().getAudioWithMetadata(voiceFrameBytes); + processMetadata(audioWithMetadata); + + ReusableAudioPacket audioPacket = getAudioPacketQueue().getBuffer(audioWithMetadata.getAudio().length); + audioPacket.resetAttributes(); + audioPacket.setAudioChannelId(getAudioChannelId()); + audioPacket.setIdentifierCollection(getIdentifierCollection().copyOf()); + audioPacket.loadAudioFrom(audioWithMetadata.getAudio()); + getAudioPacketListener().receive(audioPacket); + } + } + } + + /** + * Processes optional metadata that can be included with decoded audio (ie dtmf, tones, knox, etc.) + */ + private void processMetadata(IAudioWithMetadata audioWithMetadata) + { + if(mIdentifierUpdateNotificationListener != null) + { + if(audioWithMetadata.hasMetadata()) + { + Map metadata = audioWithMetadata.getMetadata(); + + if(metadata.containsKey(METADATA_TYPE_DTMF)) + { + String dtmf = metadata.get(METADATA_TYPE_DTMF); + + if(dtmf != null) + { + if(mDtmfMetadataProcessor == null) + { + mDtmfMetadataProcessor = new MetadataProcessor(); + } + + List dtmfTones = mDtmfMetadataProcessor.process(dtmf); + broadcast(P25DtmfIdentifier.create(dtmfTones)); + } + } + else if(metadata.containsKey(METADATA_TYPE_KNOX)) + { + String knox = metadata.get(METADATA_TYPE_KNOX); + + if(knox != null) + { + if(mKnoxMetadataProcessor == null) + { + mKnoxMetadataProcessor = new MetadataProcessor(); + } + + List knoxTones = mKnoxMetadataProcessor.process(knox); + broadcast(P25KnoxIdentifier.create(knoxTones)); + } + } + else if(metadata.containsKey(METADATA_TYPE_TONE)) + { + String tone = metadata.get(METADATA_TYPE_TONE); + + if(tone != null) + { + if(mToneMetadataProcessor == null) + { + mToneMetadataProcessor = new MetadataProcessor(); + } + + List tones = mToneMetadataProcessor.process(tone); + broadcast(P25ToneIdentifier.create(tones)); + } + } + else if(metadata.containsKey(METADATA_TYPE_CALL_PROGRESS)) + { + String callProgressTone = metadata.get(METADATA_TYPE_CALL_PROGRESS); + + if(callProgressTone != null) + { + if(mCallProcessMetadataProcessor == null) + { + mCallProcessMetadataProcessor = new MetadataProcessor(); + } + + List tones = mCallProcessMetadataProcessor.process(callProgressTone); + broadcast(P25CallProgressIdentifier.create(tones)); + } + } + } + else + { + if(mDtmfMetadataProcessor != null) + { + mDtmfMetadataProcessor.noMetadata(); + } + if(mKnoxMetadataProcessor != null) + { + mKnoxMetadataProcessor.noMetadata(); + } + if(mCallProcessMetadataProcessor != null) + { + mCallProcessMetadataProcessor.noMetadata(); + } + if(mToneMetadataProcessor != null) + { + mToneMetadataProcessor.noMetadata(); + } + } + } + } + + private void broadcast(Identifier identifier) + { + if(mIdentifierUpdateNotificationListener != null) + { + mIdentifierUpdateNotificationListener.receive(new IdentifierUpdateNotification(identifier, + IdentifierUpdateNotification.Operation.ADD, getTimeslot())); + } + } + + @Override + public void setIdentifierUpdateListener(Listener listener) + { + mIdentifierUpdateNotificationListener = listener; + } + + @Override + public void removeIdentifierUpdateListener() + { + mIdentifierUpdateNotificationListener = null; + } + + /** + * Processes metadata string values to provide a de-duplicated list of metadata values. + * + * This is necessary for metadata such as DTMF where a tone can span multiple 20ms voice frames but is intended + * to be represented as a single tone. An empty (no-metadata) frame causes the repeat checker to stop and allow + * the next metadata value to be added to the list. + */ + public class MetadataProcessor + { + private List mValues = new ArrayList<>(); + private String mLastInput; + + public List process(String value) + { + if(value != null) + { + if(mLastInput != null && mLastInput.equalsIgnoreCase(value)) + { + //Suppress the repeat and return the current value + return mValues; + } + else + { + mLastInput = value; + mValues.add(value); + return mValues; + } + } + + return mValues; + } + + public void noMetadata() + { + mLastInput = null; + } + } + + /** + * Wrapper for squelch state to process end of call actions. At call end the encrypted call state established + * flag is reset so that the encrypted audio state for the next call can be properly detected and we send an + * END audio packet so that downstream processors like the audio recorder can properly close out a call sequence. + */ + public class SquelchStateListener implements Listener + { + @Override + public void receive(SquelchStateEvent event) + { + if(event.getTimeslot() == getTimeslot() && event.getSquelchState() == SquelchState.SQUELCH) + { + if(hasAudioPacketListener()) + { + ReusableAudioPacket endAudioPacket = getAudioPacketQueue().getEndAudioBuffer(); + endAudioPacket.resetAttributes(); + endAudioPacket.setAudioChannelId(getAudioChannelId()); + endAudioPacket.setIdentifierCollection(getIdentifierCollection().copyOf()); + endAudioPacket.incrementUserCount(); + getAudioPacketListener().receive(endAudioPacket); + } + + reset(); + } + } + } + +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25P2CallSequenceRecorder.java b/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25P2CallSequenceRecorder.java new file mode 100644 index 000000000..3d7ea8820 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/audio/P25P2CallSequenceRecorder.java @@ -0,0 +1,358 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +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.message.IMessage; +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.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 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. + */ +public class P25P2CallSequenceRecorder extends MBECallSequenceRecorder +{ + private final static Logger mLog = LoggerFactory.getLogger(P25P2CallSequenceRecorder.class); + + private static final String PROTOCOL = "APCO25-PHASE2"; + + private TimeslotCallSequenceProcessor mTimeslot0Processor = new TimeslotCallSequenceProcessor(0); + private TimeslotCallSequenceProcessor mTimeslot1Processor = new TimeslotCallSequenceProcessor(1); + + /** + * Constructs a P25-Phase2 MBE call sequence recorder. + * + * @param userPreferences to obtain the recording directory + * @param channelFrequency for the channel to record + */ + public P25P2CallSequenceRecorder(UserPreferences userPreferences, long channelFrequency, String system, String site) + { + super(userPreferences, channelFrequency, system, site); + } + + /** + * Stops and flushes any partial frame sequence from the processors + */ + @Override + public void stop() + { + mTimeslot0Processor.flush(); + mTimeslot1Processor.flush(); + } + + /** + * Primary message interface for receiving frames and metadata messages to record + */ + @Override + public void receive(IMessage message) + { + if(message instanceof P25P2Message) + { + P25P2Message p25p2 = (P25P2Message)message; + + if(p25p2.isValid()) + { + switch(p25p2.getTimeslot()) + { + case 0: + mTimeslot0Processor.process(p25p2); + break; + case 1: + mTimeslot1Processor.process(p25p2); + break; + } + } + } + } + + /** + * Timeslot call sequence processor + */ + class TimeslotCallSequenceProcessor + { + private int mTimeslot; + private MBECallSequence mCallSequence; + + /** + * Constructs a processor for the specified channel number / timeslot + * @param timeslot + */ + public TimeslotCallSequenceProcessor(int timeslot) + { + mTimeslot = timeslot; + } + + /** + * Timeslot for this processor + */ + public int getTimeslot() + { + return mTimeslot; + } + + /** + * Flushes any partial call sequence + */ + public void flush() + { + if(mCallSequence != null) + { + writeCallSequence(mCallSequence, "TS" + getTimeslot()); + mCallSequence = null; + } + } + + /** + * Processes any P25 Phase 2 message + */ + public void process(P25P2Message message) + { + if(message instanceof AbstractVoiceTimeslot) + { + process((AbstractVoiceTimeslot)message); + } + else if(message instanceof MacMessage) + { + process((MacMessage)message); + } + } + + /** + * Processes Voice timeslots + */ + private void process(AbstractVoiceTimeslot voiceTimeslot) + { + if(mCallSequence == null) + { + mCallSequence = new MBECallSequence(PROTOCOL); + } + + List voiceFrames = voiceTimeslot.getVoiceFrames(); + + long baseTimestamp = voiceTimeslot.getTimestamp(); + + for(BinaryMessage frame : voiceFrames) + { + mCallSequence.addVoiceFrame(baseTimestamp, frame.toHexString()); + + //Voice frames are 20 milliseconds each, so we increment the timestamp by 20 for each one + baseTimestamp += 20; + } + } + + /** + * Processes a MAC message + */ + private void process(MacMessage macMessage) + { + switch(macMessage.getMacPduType()) + { + case MAC_1_PTT: + case MAC_4_ACTIVE: + process(macMessage.getMacStructure(), true); + break; + case MAC_2_END_PTT: + case MAC_6_HANGTIME: + process(macMessage.getMacStructure(), false); + break; + case MAC_3_IDLE: + flush(); + break; + } + + } + + /** + * Processes a mac structure message to obtain from/to identifiers and to optionally close the call sequence + * when the MAC pdu indicates that the call sequence is no longer active + * + * @param mac + * @param isActive + */ + private void process(MacStructure mac, boolean isActive) + { + if(mCallSequence == null && isActive) + { + mCallSequence = new MBECallSequence(PROTOCOL); + } + + if(mCallSequence != null) + { + switch(mac.getOpcode()) + { + case PUSH_TO_TALK: + if(mac instanceof PushToTalk) + { + PushToTalk ptt = (PushToTalk)mac; + + if(mCallSequence == null) + { + mCallSequence = new MBECallSequence(PROTOCOL); + } + mCallSequence.setFromIdentifier(ptt.getSourceAddress().toString()); + mCallSequence.setToIdentifier(ptt.getGroupAddress().toString()); + + if(ptt.isEncrypted()) + { + mCallSequence.setEncrypted(true); + mCallSequence.setEncryptionSyncParameters(ptt.getEncryptionSyncParameters()); + } + } + else + { + mLog.warn("Expected push-to-talk structure but found: " + mac.getClass()); + } + break; + case END_PUSH_TO_TALK: + if(mac instanceof EndPushToTalk) + { + EndPushToTalk eptt = (EndPushToTalk)mac; + + String source = eptt.getSourceAddress().toString(); + + if(source != null && !source.contentEquals("16777215")) + { + mCallSequence.setFromIdentifier(source); + } + mCallSequence.setToIdentifier(eptt.getGroupAddress().toString()); + writeCallSequence(mCallSequence, "TS" + getTimeslot()); + mCallSequence = null; + } + else + { + mLog.warn("Expected End push-to-talk structure but found: " + mac.getClass()); + } + break; + case TDMA_1_GROUP_VOICE_CHANNEL_USER_ABBREVIATED: + if(mac instanceof GroupVoiceChannelUserAbbreviated) + { + GroupVoiceChannelUserAbbreviated gvcua = (GroupVoiceChannelUserAbbreviated)mac; + mCallSequence.setFromIdentifier(gvcua.getSourceAddress().toString()); + mCallSequence.setToIdentifier(gvcua.getGroupAddress().toString()); + mCallSequence.setCallType(CALL_TYPE_GROUP); + if(gvcua.getServiceOptions().isEncrypted()) + { + mCallSequence.setEncrypted(true); + } + } + else + { + mLog.warn("Expected group voice channel user abbreviated but found: " + mac.getClass()); + } + break; + case TDMA_2_UNIT_TO_UNIT_VOICE_CHANNEL_USER: + if(mac instanceof UnitToUnitVoiceChannelUserAbbreviated) + { + UnitToUnitVoiceChannelUserAbbreviated uuvcua = (UnitToUnitVoiceChannelUserAbbreviated)mac; + mCallSequence.setFromIdentifier(uuvcua.getSourceAddress().toString()); + mCallSequence.setToIdentifier(uuvcua.getTargetAddress().toString()); + mCallSequence.setCallType(CALL_TYPE_INDIVIDUAL); + if(uuvcua.getServiceOptions().isEncrypted()) + { + mCallSequence.setEncrypted(true); + } + } + else + { + mLog.warn("Expected unit-2-unit voice channel user abbreviated but found: " + mac.getClass()); + } + break; + case TDMA_3_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER: + if(mac instanceof TelephoneInterconnectVoiceChannelUser) + { + TelephoneInterconnectVoiceChannelUser tivcu = (TelephoneInterconnectVoiceChannelUser)mac; + mCallSequence.setToIdentifier(tivcu.getToOrFromAddress().toString()); + mCallSequence.setCallType(CALL_TYPE_TELEPHONE_INTERCONNECT); + if(tivcu.getServiceOptions().isEncrypted()) + { + mCallSequence.setEncrypted(true); + } + } + else + { + mLog.warn("Expected telephone interconnect voice channel user abbreviated but found: " + mac.getClass()); + } + break; + case TDMA_33_GROUP_VOICE_CHANNEL_USER_EXTENDED: + if(mac instanceof GroupVoiceChannelUserExtended) + { + GroupVoiceChannelUserExtended gvcue = (GroupVoiceChannelUserExtended)mac; + mCallSequence.setFromIdentifier(gvcue.getSourceAddress().toString()); + mCallSequence.setToIdentifier(gvcue.getGroupAddress().toString()); + mCallSequence.setCallType(CALL_TYPE_GROUP); + if(gvcue.getServiceOptions().isEncrypted()) + { + mCallSequence.setEncrypted(true); + } + } + else + { + mLog.warn("Expected group voice channel user extended but found: " + mac.getClass()); + } + break; + case TDMA_34_UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED: + if(mac instanceof UnitToUnitVoiceChannelUserExtended) + { + UnitToUnitVoiceChannelUserExtended uuvcue = (UnitToUnitVoiceChannelUserExtended)mac; + mCallSequence.setFromIdentifier(uuvcue.getSourceAddress().toString()); + mCallSequence.setToIdentifier(uuvcue.getTargetAddress().toString()); + mCallSequence.setCallType(CALL_TYPE_INDIVIDUAL); + if(uuvcue.getServiceOptions().isEncrypted()) + { + mCallSequence.setEncrypted(true); + } + } + else + { + mLog.warn("Expected unit-2-unit voice channel user extended but found: " + mac.getClass()); + } + break; + } + + if(!isActive) + { + writeCallSequence(mCallSequence, "TS" + getTimeslot()); + mCallSequence = null; + } + } + } + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/audio/Phase2EncryptionSyncParameters.java b/src/main/java/io/github/dsheirer/module/decode/p25/audio/Phase2EncryptionSyncParameters.java new file mode 100644 index 000000000..930c74175 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/audio/Phase2EncryptionSyncParameters.java @@ -0,0 +1,50 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.audio; + +import io.github.dsheirer.audio.codec.mbe.IEncryptionSyncParameters; +import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier; + +public class Phase2EncryptionSyncParameters implements IEncryptionSyncParameters +{ + private EncryptionKeyIdentifier mEncryptionKeyIdentifier; + private String mMessageIndicator; + + public Phase2EncryptionSyncParameters(EncryptionKeyIdentifier encryptionKeyIdentifier, String messageIndicator) + { + mEncryptionKeyIdentifier = encryptionKeyIdentifier; + mMessageIndicator = messageIndicator; + } + + @Override + public EncryptionKeyIdentifier getEncryptionKey() + { + return mEncryptionKeyIdentifier; + } + + @Override + public String getMessageIndicator() + { + return mMessageIndicator; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/audio/VoiceFrame.java b/src/main/java/io/github/dsheirer/module/decode/p25/audio/VoiceFrame.java new file mode 100644 index 000000000..c7c9d0900 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/audio/VoiceFrame.java @@ -0,0 +1,172 @@ +/******************************************************************************* + * sdr-trunk + * 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 + * + ******************************************************************************/ + +package io.github.dsheirer.module.decode.p25.audio; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonRootName; + +/** + * Voice frame using hexadecimal representation of the transmitted voice and ecc bits + */ +@JsonRootName(value = "frame") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"encryption_algorithm", "encryption_key_id", "encryption_mi", "time", "hex"}) +public class VoiceFrame +{ + private long mTimestamp; + private String mFrame; + private Integer mAlgorithm; + private Integer mKeyId; + private String mMessageIndicator; + + public VoiceFrame() + { + //no-arg constructor for faster jackson deserialization + } + + /** + * Constructs an unencrypted voice frame + * + * @param timestamp the frame was transmitted + * @param frame with voice and ecc bits + */ + public VoiceFrame(long timestamp, String frame) + { + mTimestamp = timestamp; + mFrame = frame; + } + + /** + * Constructs an encrypted voice frame + * + * @param timestamp the message was transmitted + * @param frame of hexadecimal values + * @param algorithm used to encrypt the voice frame + * @param keyid used to encrypt the voice frame + * @param messageIndicator for the key generator fill + */ + public VoiceFrame(long timestamp, String frame, int algorithm, int keyid, String messageIndicator) + { + this(timestamp, frame); + mAlgorithm = algorithm; + mKeyId = keyid; + mMessageIndicator = messageIndicator; + } + + /** + * Timestamp the frame was transmitted + * + * @return timestamp in milliseconds since epoch (1970) + */ + @JsonProperty("time") + public long getTimestamp() + { + return mTimestamp; + } + + public void setTimestamp(long timestamp) + { + mTimestamp = timestamp; + } + + /** + * Transmitted voice frame and ecc bits in hexadecimal + */ + @JsonProperty("hex") + public String getFrame() + { + return mFrame; + } + + public void setFrame(String frame) + { + mFrame = frame; + } + + /** + * Audio frame bytes + * @return frame bytes or null + */ + @JsonIgnore + public byte[] getFrameBytes() + { + if(mFrame != null) + { + byte[] bytes = new byte[mFrame.length() / 2]; + for(int x = 0; x < mFrame.length(); x += 2) + { + String hex = mFrame.substring(x, x + 2); + bytes[x / 2] = (byte) (0xFF & Integer.parseInt(hex, 16)); + } + + return bytes; + } + + return null; + } + + /** + * Algorithm identifier numeric value + * + * @return algorithm id + */ + @JsonProperty("encryption_algorithm") + public Integer getAlgorithm() + { + return mAlgorithm; + } + + public void setAlgorithm(int algorithm) + { + mAlgorithm = algorithm; + } + + /** + * Key identifier + * + * @return key id + */ + @JsonProperty("encryption_key_id") + public Integer getKeyId() + { + return mKeyId; + } + + public void setKeyId(int keyId) + { + mKeyId = keyId; + } + + /** + * Key generator fill values + * + * @return message indicator + */ + @JsonProperty("encryption_mi") + public String getMessageIndicator() + { + return mMessageIndicator; + } + + public void setMessageIndicator(String messageIndicator) + { + mMessageIndicator = messageIndicator; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/APCO25Channel.java b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/APCO25Channel.java index e87dffe81..da34f1480 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/APCO25Channel.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/APCO25Channel.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.p25.identifier.channel; @@ -24,7 +26,7 @@ import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.identifier.IdentifierClass; import io.github.dsheirer.identifier.Role; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; import io.github.dsheirer.protocol.Protocol; /** @@ -92,6 +94,15 @@ public long getUplinkFrequency() return getValue().getUplinkFrequency(); } + /** + * Timeslot for this channel + * @return timeslot + */ + public int getTimeslot() + { + return getValue().getTimeslot(); + } + /** * Creates a new APCO-25 identifier diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25Channel.java b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25Channel.java index 954d52139..e157ae274 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25Channel.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25Channel.java @@ -1,27 +1,29 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.p25.identifier.channel; import io.github.dsheirer.channel.IChannelDescriptor; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; import io.github.dsheirer.protocol.Protocol; import java.util.Objects; @@ -131,7 +133,7 @@ public int getTimeslotCount() return mFrequencyBand.getTimeslotCount(); } - return 0; + return 1; } @Override @@ -145,6 +147,38 @@ public boolean isTDMAChannel() return false; } + /** + * Timeslot for a TDMA channel + * @return timeslot or 0 if the channel is not a TDMA channel + */ + public int getTimeslot() + { + if(isTDMAChannel()) + { + return getDownlinkChannelNumber() % getTimeslotCount(); + } + + return 0; + } + + /** + * Logical channel number. For Phase 1 channels this is the downlink channel number. For Phase 2 channels, this + * is the channel number without the timeslot specifier. + */ + public int getDownlinkLogicalChannelNumber() + { + return getDownlinkChannelNumber() / getTimeslotCount(); + } + + /** + * Logical channel number. For Phase 1 channels this is the uplink channel number. For Phase 2 channels, this + * is the channel number without the timeslot specifier. + */ + public int getUplinkLogicalChannelNumber() + { + return getUplinkChannelNumber() / getTimeslotCount(); + } + /** * Formatted channel number */ @@ -152,19 +186,26 @@ public String toString() { if(getDownlinkBandIdentifier() == getUplinkBandIdentifier() && getDownlinkChannelNumber() == getUplinkChannelNumber()) { - return getDownlinkBandIdentifier() + "-" + getDownlinkChannelNumber(); + return getDownlinkBandIdentifier() + "-" + (getDownlinkLogicalChannelNumber()); } else if(hasUplinkChannel()) { - return getDownlinkBandIdentifier() + "-" + getDownlinkChannelNumber() + "/" + - getUplinkBandIdentifier() + "-" + getUplinkChannelNumber(); + return getDownlinkBandIdentifier() + "-" + (getDownlinkLogicalChannelNumber()) + "/" + + getUplinkBandIdentifier() + "-" + (getUplinkLogicalChannelNumber()); } else { - return getDownlinkBandIdentifier() + "-" + getDownlinkChannelNumber() + "/-----"; + return getDownlinkBandIdentifier() + "-" + (getDownlinkLogicalChannelNumber()) + "/-----"; } } + /** + * Designates channel equality as having the same band identifier and channel number. + * + * Note: Phase 2 channels also specify timeslot for a channel, but timeslot is not considered for equality. + * @param o other object + * @return true if both instances are P25 channels in the same band and channel number + */ @Override public boolean equals(Object o) { @@ -172,18 +213,21 @@ public boolean equals(Object o) { return true; } - if(o == null || getClass() != o.getClass()) + if(o == null) + { + return false; + } + if(!(o instanceof P25Channel)) { return false; } P25Channel that = (P25Channel)o; - return mBandIdentifier == that.mBandIdentifier && - mChannelNumber == that.mChannelNumber; + return mBandIdentifier == that.mBandIdentifier && getDownlinkLogicalChannelNumber() == that.getDownlinkLogicalChannelNumber(); } @Override public int hashCode() { - return Objects.hash(mBandIdentifier, mChannelNumber); + return Objects.hash(mBandIdentifier, getDownlinkLogicalChannelNumber()); } } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25ExplicitChannel.java b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25ExplicitChannel.java index 0b696e2f5..87f8f003d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25ExplicitChannel.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25ExplicitChannel.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -20,7 +20,7 @@ package io.github.dsheirer.module.decode.p25.identifier.channel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; public class P25ExplicitChannel extends P25Channel implements Comparable { diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25P2Channel.java b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25P2Channel.java new file mode 100644 index 000000000..3efb079c8 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25P2Channel.java @@ -0,0 +1,46 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.identifier.channel; + +/** + * P25 Phase II Channel. Note: this channel is hard-coded for 2 timeslots, independent of the band identifier. + */ +public class P25P2Channel extends P25Channel +{ + public P25P2Channel(int bandIdentifier, int channelNumber) + { + super(bandIdentifier, channelNumber); + } + + @Override + public int getTimeslotCount() + { + return 2; + } + + @Override + public boolean isTDMAChannel() + { + return true; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25P2ExplicitChannel.java b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25P2ExplicitChannel.java new file mode 100644 index 000000000..3b960f690 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/channel/P25P2ExplicitChannel.java @@ -0,0 +1,53 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.identifier.channel; + +/** + * Explicit P25 Phase 2 channel. + */ +public class P25P2ExplicitChannel extends P25ExplicitChannel +{ + /** + * Constructs an instance + * @param downlinkBandIdentifier + * @param downlinkChannelNumber + * @param uplinkBandIdentifier + * @param uplinkChannelNumber + */ + public P25P2ExplicitChannel(int downlinkBandIdentifier, int downlinkChannelNumber, int uplinkBandIdentifier, int uplinkChannelNumber) + { + super(downlinkBandIdentifier, downlinkChannelNumber, uplinkBandIdentifier, uplinkChannelNumber); + } + + @Override + public int getTimeslotCount() + { + return 2; + } + + @Override + public boolean isTDMAChannel() + { + return true; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/identifier/encryption/APCO25EncryptionKey.java b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/encryption/APCO25EncryptionKey.java index 9c933a75c..89d748252 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/identifier/encryption/APCO25EncryptionKey.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/encryption/APCO25EncryptionKey.java @@ -1,49 +1,78 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.p25.identifier.encryption; -import io.github.dsheirer.identifier.Form; -import io.github.dsheirer.identifier.IdentifierClass; -import io.github.dsheirer.identifier.Role; import io.github.dsheirer.identifier.encryption.EncryptionKey; -import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier; -import io.github.dsheirer.protocol.Protocol; +import io.github.dsheirer.module.decode.p25.reference.Encryption; -public class APCO25EncryptionKey extends EncryptionKeyIdentifier +public class APCO25EncryptionKey extends EncryptionKey { - public APCO25EncryptionKey(EncryptionKey encryptionKey) + public APCO25EncryptionKey(int algorithm, int keyId) { - super(encryptionKey, IdentifierClass.NETWORK, Form.ENCRYPTION_KEY, Role.BROADCAST); + super(algorithm, keyId); + } + + public Encryption getEncryptionAlgorithm() + { + return Encryption.fromValue(getAlgorithm()); + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + + if(isEncrypted()) + { + Encryption encryption = getEncryptionAlgorithm(); + + if(encryption == Encryption.UNKNOWN) + { + sb.append("ALGORITHM ID:").append(getAlgorithm()); + } + else + { + sb.append("ENCRYPTION:").append(getEncryptionAlgorithm()); + } + + sb.append(" KEY:").append(getKey()); + } + else + { + sb.append("NO ENCRYPTION"); + } + return sb.toString(); } @Override - public Protocol getProtocol() + public boolean isEncrypted() { - return Protocol.APCO25; + return getEncryptionAlgorithm() != Encryption.UNENCRYPTED; } /** * Creates a new APCO-25 encryption algorithm */ - public static APCO25EncryptionKey create(int alogorithm, int keyId) + public static APCO25EncryptionKey create(int algorithm, int keyId) { - return new APCO25EncryptionKey(new EncryptionKey(alogorithm, keyId)); + return new APCO25EncryptionKey(algorithm, keyId); } } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/identifier/talkgroup/APCO25FullyQualifiedIdentifier.java b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/talkgroup/APCO25FullyQualifiedIdentifier.java new file mode 100644 index 000000000..e351e0795 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/identifier/talkgroup/APCO25FullyQualifiedIdentifier.java @@ -0,0 +1,57 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.identifier.talkgroup; + +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.talkgroup.FullyQualifiedIdentifier; +import io.github.dsheirer.protocol.Protocol; + +/** + * Fully Qualified Radio Identifier (talkgroup) that includes WACN, System, and Radio Address. + */ +public class APCO25FullyQualifiedIdentifier extends Identifier +{ + public APCO25FullyQualifiedIdentifier(FullyQualifiedIdentifier value, Role role) + { + super(value, IdentifierClass.USER, Form.FULLY_QUALIFIED_IDENTIFIER, role); + } + + @Override + public Protocol getProtocol() + { + return Protocol.APCO25; + } + + public static APCO25FullyQualifiedIdentifier createFrom(int wacn, int system, int id) + { + return new APCO25FullyQualifiedIdentifier(FullyQualifiedIdentifier.create(wacn, system, id), Role.FROM); + } + + public static APCO25FullyQualifiedIdentifier createTo(int wacn, int system, int id) + { + return new APCO25FullyQualifiedIdentifier(FullyQualifiedIdentifier.create(wacn, system, id), Role.TO); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/IAdjacentSite.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/IAdjacentSite.java deleted file mode 100644 index 7d068e855..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/IAdjacentSite.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.github.dsheirer.module.decode.p25.message; - -import io.github.dsheirer.channel.IChannelDescriptor; -import io.github.dsheirer.identifier.Identifier; - -/** - * Interface for adjacent site (ie neighbor) messages - */ -public interface IAdjacentSite -{ - String getUniqueID(); - - Identifier getRFSSId(); - - Identifier getSystemID(); - - Identifier getSiteID(); - - Identifier getLRAId(); - - String getSystemServiceClass(); - - IChannelDescriptor getChannel(); -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/HDUMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/HDUMessageFilter.java deleted file mode 100644 index 5e7d88d34..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/HDUMessageFilter.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.dsheirer.module.decode.p25.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.message.hdu.HDUMessage; - -import java.util.Collections; -import java.util.List; - -public class HDUMessageFilter extends Filter -{ - public HDUMessageFilter() - { - super("Header Data Unit"); - } - - @Override - public boolean passes(IMessage message) - { - return mEnabled && canProcess(message); - } - - @Override - public boolean canProcess(IMessage message) - { - return message instanceof HDUMessage; - } - - @Override - public List> getFilterElements() - { - return Collections.EMPTY_LIST; - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/LDUMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/LDUMessageFilter.java deleted file mode 100644 index febf1a915..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/LDUMessageFilter.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.dsheirer.module.decode.p25.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.message.ldu.LDUMessage; - -import java.util.Collections; -import java.util.List; - -public class LDUMessageFilter extends Filter -{ - public LDUMessageFilter() - { - super("Link Data Unit"); - } - - @Override - public boolean passes(IMessage message) - { - return mEnabled && canProcess(message); - } - - @Override - public boolean canProcess(IMessage message) - { - return message instanceof LDUMessage; - } - - @Override - public List> getFilterElements() - { - return Collections.EMPTY_LIST; - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/P25MessageFilterSet.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/P25MessageFilterSet.java deleted file mode 100644 index 8f6993bb3..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/P25MessageFilterSet.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.dsheirer.module.decode.p25.message.filter; - -import io.github.dsheirer.filter.FilterSet; -import io.github.dsheirer.message.IMessage; -import io.github.dsheirer.message.SyncLossMessage; -import io.github.dsheirer.module.decode.p25.message.P25Message; - -public class P25MessageFilterSet extends FilterSet -{ - public P25MessageFilterSet() - { - super("P25 Message Filter"); - - addFilter(new AMBTCMessageFilter()); - addFilter(new HDUMessageFilter()); - addFilter(new IPPacketMessageFilter()); - addFilter(new LDUMessageFilter()); - addFilter(new PDUMessageFilter()); - addFilter(new SNDCPMessageFilter()); - addFilter(new SyncLossMessageFilter()); - addFilter(new TDUMessageFilter()); - addFilter(new TDULCMessageFilter()); - addFilter(new TSBKMessageFilterSet()); - addFilter(new UMBTCMessageFilter()); - } - - @Override - public boolean canProcess(IMessage message) - { - return message instanceof P25Message || message instanceof SyncLossMessage; - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/TDULCMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/TDULCMessageFilter.java deleted file mode 100644 index 7266535c8..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/TDULCMessageFilter.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.dsheirer.module.decode.p25.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.message.tdu.TDULinkControlMessage; - -import java.util.Collections; -import java.util.List; - -public class TDULCMessageFilter extends Filter -{ - public TDULCMessageFilter() - { - super("TDU Terminator Data Unit with Link Control"); - } - - @Override - public boolean passes(IMessage message) - { - return mEnabled && canProcess(message); - } - - @Override - public boolean canProcess(IMessage message) - { - return message instanceof TDULinkControlMessage; - } - - @Override - public List> getFilterElements() - { - return Collections.EMPTY_LIST; - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/TDUMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/TDUMessageFilter.java deleted file mode 100644 index 97dfa4c08..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/TDUMessageFilter.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.dsheirer.module.decode.p25.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.message.tdu.TDUMessage; - -import java.util.Collections; -import java.util.List; - -public class TDUMessageFilter extends Filter -{ - public TDUMessageFilter() - { - super("TDU Terminator Data Unit"); - } - - @Override - public boolean passes(IMessage message) - { - return mEnabled && canProcess(message); - } - - @Override - public boolean canProcess(IMessage message) - { - return message instanceof TDUMessage; - } - - @Override - public List> getFilterElements() - { - return Collections.EMPTY_LIST; - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/UnknownLinkControlWord.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/UnknownLinkControlWord.java deleted file mode 100644 index 27445e6d0..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/UnknownLinkControlWord.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.dsheirer.module.decode.p25.message.lc; - -import io.github.dsheirer.bits.BinaryMessage; -import io.github.dsheirer.identifier.Identifier; - -import java.util.Collections; -import java.util.List; - -/** - * Unknown link control word. - */ -public class UnknownLinkControlWord extends LinkControlWord -{ - /** - * Constructs a Link Control Word from the binary message sequence. - * - * @param message - */ - public UnknownLinkControlWord(BinaryMessage message) - { - super(message); - } - - @Override - public List getIdentifiers() - { - return Collections.EMPTY_LIST; - } - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append(getMessageStub()); - sb.append(" UNKNOWN/UNRECOGNIZED OPCODE"); - sb.append(" MSG:").append(getMessage().toHexString()); - return sb.toString(); - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUSequenceMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUSequenceMessage.java deleted file mode 100644 index e86b759fd..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUSequenceMessage.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.dsheirer.module.decode.p25.message.pdu; - -import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; - -import java.util.Collections; -import java.util.List; - -public class PDUSequenceMessage extends P25Message -{ - private PDUSequence mPDUSequence; - - public PDUSequenceMessage(PDUSequence PDUSequence, int nac, long timestamp) - { - super(null, nac, timestamp); - mPDUSequence = PDUSequence; - } - - public PDUSequence getPDUSequence() - { - return mPDUSequence; - } - - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append(getPDUSequence().toString()); - return sb.toString(); - } - - @Override - public DataUnitID getDUID() - { - return DataUnitID.PACKET_DATA_UNIT; - } - - @Override - public List getIdentifiers() - { - return Collections.EMPTY_LIST; - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/ISPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/ISPMessage.java deleted file mode 100644 index 95ffa3875..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/ISPMessage.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk; - -import io.github.dsheirer.bits.CorrectedBinaryMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; -import io.github.dsheirer.module.decode.p25.reference.Direction; - -/** - * P25 Inbound (ISP) TSBK Message - */ -public abstract class ISPMessage extends TSBKMessage -{ - /** - * Constructs an inbound (ISP) TSBK from the binary message sequence. - * - * @param dataUnitID TSBK1/2/3 - * @param message binary sequence - * @param nac decoded from the NID - * @param timestamp for the message - */ - public ISPMessage(DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestamp) - { - super(dataUnitID, message, nac, timestamp); - } - - @Override - public Direction getDirection() - { - return Direction.INBOUND; - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/OSPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/OSPMessage.java deleted file mode 100644 index 4c33ded50..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/OSPMessage.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk; - -import io.github.dsheirer.bits.CorrectedBinaryMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; -import io.github.dsheirer.module.decode.p25.reference.Direction; - -/** - * P25 Outbound (OSP) TSBK Message - */ -public abstract class OSPMessage extends TSBKMessage -{ - /** - * Constructs an outbound (OSP) TSBK from the binary message sequence. - * - * @param dataUnitID TSBK1/2/3 - * @param message binary sequence - * @param nac decoded from the NID - * @param timestamp for the message - */ - public OSPMessage(DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestamp) - { - super(dataUnitID, message, nac, timestamp); - } - - @Override - public Direction getDirection() - { - return Direction.OUTBOUND; - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnknownISPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnknownISPMessage.java deleted file mode 100644 index c74c1f331..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnknownISPMessage.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; - -import io.github.dsheirer.bits.CorrectedBinaryMessage; -import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; - -import java.util.Collections; -import java.util.List; - -/** - * Unknown/Unrecognized opcode message. - */ -public class UnknownISPMessage extends ISPMessage -{ - /** - * Constructs a TSBK from the binary message sequence. - */ - public UnknownISPMessage(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) - { - super(dataUnitId, message, nac, timestamp); - } - - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append(getMessageStub()); - sb.append(" **UNRECOGNIZED ISP OPCODE**"); - sb.append(" MSG:").append(getMessage().toHexString()); - return sb.toString(); - } - - @Override - public List getIdentifiers() - { - return Collections.EMPTY_LIST; - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnknownOSPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnknownOSPMessage.java deleted file mode 100644 index aa2b25957..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnknownOSPMessage.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; - -import io.github.dsheirer.bits.CorrectedBinaryMessage; -import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; - -import java.util.Collections; -import java.util.List; - -/** - * Unknown/Unrecognized opcode message. - */ -public class UnknownOSPMessage extends OSPMessage -{ - /** - * Constructs a TSBK from the binary message sequence. - */ - public UnknownOSPMessage(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) - { - super(dataUnitId, message, nac, timestamp); - } - - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append(getMessageStub()); - sb.append(" **UNRECOGNIZED OSP OPCODE**"); - sb.append(" MSG:").append(getMessage().toHexString()); - return sb.toString(); - } - - @Override - public List getIdentifiers() - { - return Collections.EMPTY_LIST; - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/vselp/VSELP1Message.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/vselp/VSELP1Message.java deleted file mode 100644 index ba8766300..000000000 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/vselp/VSELP1Message.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.dsheirer.module.decode.p25.message.vselp; - -import io.github.dsheirer.bits.CorrectedBinaryMessage; -import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; - -import java.util.Collections; -import java.util.List; - -public class VSELP1Message extends P25Message -{ - /** - * Motorola VSELP audio message 1 - not implemented. - */ - public VSELP1Message(CorrectedBinaryMessage message, int nac, long timestamp) - { - super(message, nac, timestamp); - } - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append(getMessageStub()); - sb.append(" MSG:").append(getMessage().toHexString()); - return sb.toString(); - } - - @Override - public DataUnitID getDUID() - { - return DataUnitID.VSELP1; - } - - @Override - public List getIdentifiers() - { - return Collections.EMPTY_LIST; - } -} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25Metadata.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/C4FMFrameListener.java similarity index 64% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25Metadata.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/C4FMFrameListener.java index 09da35e94..da90b22ed 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25Metadata.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/C4FMFrameListener.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,20 +18,18 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25; +package io.github.dsheirer.module.decode.p25.phase1; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.bits.BinaryMessage; -/** - * Decoded metadata for an APCO25 channel - */ -public class P25Metadata implements Listener +public interface C4FMFrameListener { + /** + * Listener interface to receive the output of the C4FMMessageFramer. + * + * @param buffer - framed message without the sync pattern + * @param inverted - flag indicating if the message was received inverted + */ + public void receive( BinaryMessage buffer, boolean inverted ); - @Override - public void receive(P25Message p25Message) - { - - } } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/C4FMSlicer.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/C4FMSlicer.java similarity index 64% rename from src/main/java/io/github/dsheirer/module/decode/p25/C4FMSlicer.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/C4FMSlicer.java index afdac1f3d..eb05a16a3 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/C4FMSlicer.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/C4FMSlicer.java @@ -1,4 +1,24 @@ -package io.github.dsheirer.module.decode.p25; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.dsp.symbol.Dibit; import io.github.dsheirer.sample.Broadcaster; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/C4FMSymbolFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/C4FMSymbolFilter.java similarity index 96% rename from src/main/java/io/github/dsheirer/module/decode/p25/C4FMSymbolFilter.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/C4FMSymbolFilter.java index 3ad8e86b8..992294af5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/C4FMSymbolFilter.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/C4FMSymbolFilter.java @@ -1,4 +1,24 @@ -package io.github.dsheirer.module.decode.p25; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.dsp.gain.DirectGainControl; import io.github.dsheirer.sample.Listener; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/DecodeConfigP25Phase1.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/DecodeConfigP25Phase1.java similarity index 68% rename from src/main/java/io/github/dsheirer/module/decode/p25/DecodeConfigP25Phase1.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/DecodeConfigP25Phase1.java index d9300630c..db1b2fc4a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/DecodeConfigP25Phase1.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/DecodeConfigP25Phase1.java @@ -1,21 +1,23 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25; + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ +package io.github.dsheirer.module.decode.p25.phase1; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -26,7 +28,7 @@ public class DecodeConfigP25Phase1 extends DecodeConfiguration { - private P25DecoderLSM.Modulation mModulation = P25Decoder.Modulation.C4FM; + private P25P1Decoder.Modulation mModulation = P25P1Decoder.Modulation.C4FM; private int mCallTimeout = 1; private int mTrafficChannelPoolSize = TRAFFIC_CHANNEL_LIMIT_DEFAULT; @@ -43,12 +45,12 @@ public DecoderType getDecoderType() } @JacksonXmlProperty(isAttribute = true, localName = "modulation") - public P25DecoderLSM.Modulation getModulation() + public P25P1Decoder.Modulation getModulation() { return mModulation; } - public void setModulation(P25DecoderLSM.Modulation modulation) + public void setModulation(P25P1Decoder.Modulation modulation) { mModulation = modulation; } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/IDataUnitDetectListener.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/IP25P1DataUnitDetectListener.java similarity index 55% rename from src/main/java/io/github/dsheirer/module/decode/p25/IDataUnitDetectListener.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/IP25P1DataUnitDetectListener.java index 1af23a80f..c94ed31fe 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/IDataUnitDetectListener.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/IP25P1DataUnitDetectListener.java @@ -1,27 +1,29 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25; - -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ +package io.github.dsheirer.module.decode.p25.phase1; /** * Listener interface to be notified each time a P25 sync pattern and data unit has been detected * and the data unit is correct after error detection and correction and/or when the sync has been lost. */ -public interface IDataUnitDetectListener +public interface IP25P1DataUnitDetectListener { /** * Indicates that a P25 sync has been detected and a P25 data unit was successfully decoded. @@ -31,7 +33,7 @@ public interface IDataUnitDetectListener * @param bitErrors detected and corrected from both the sync pattern and the NID. * @param correctedNid bits corrected by the BCH error correction code (temporary until message parsers are updated */ - void dataUnitDetected(DataUnitID dataUnitID, int nac, int bitErrors, int discardedDibits, int[] correctedNid); + void dataUnitDetected(P25P1DataUnitID dataUnitID, int nac, int bitErrors, int discardedDibits, int[] correctedNid); /** * Indicates that sync has been lost on the dibit stream diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25ChannelStatusProcessor.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1ChannelStatusProcessor.java similarity index 71% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25ChannelStatusProcessor.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1ChannelStatusProcessor.java index 8fdfb8faa..62f6a6c21 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25ChannelStatusProcessor.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1ChannelStatusProcessor.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25; +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.dsp.symbol.Dibit; import io.github.dsheirer.module.decode.p25.reference.Direction; @@ -32,7 +32,7 @@ * Dibits 01 and 11 are used by the repeater. * Dibit 10 is used by both and is ignored by this processor. */ -public class P25ChannelStatusProcessor implements Listener +public class P25P1ChannelStatusProcessor implements Listener { private int mSubscriberCount = 0; private int mRepeaterCount = 0; @@ -56,26 +56,27 @@ public void receive(Dibit status) private void update() { - if(mRepeaterCount > mSubscriberCount) - { - mDirection = Direction.OUTBOUND; - - if(mRepeaterCount == Integer.MAX_VALUE) - { - mRepeaterCount = 1000; - mSubscriberCount = 0; - } - } - else - { - mDirection = Direction.INBOUND; - - if(mSubscriberCount == Integer.MAX_VALUE) - { - mSubscriberCount = 1000; - mRepeaterCount = 0; - } - } + //This doesn't appear to be reliable and sometimes it fails on Harris systems. +// if(mRepeaterCount > mSubscriberCount) +// { +// mDirection = Direction.OUTBOUND; +// +// if(mRepeaterCount == Integer.MAX_VALUE) +// { +// mRepeaterCount = 1000; +// mSubscriberCount = 0; +// } +// } +// else +// { +// mDirection = Direction.INBOUND; +// +// if(mSubscriberCount == Integer.MAX_VALUE) +// { +// mSubscriberCount = 1000; +// mRepeaterCount = 0; +// } +// } } public Direction getDirection() diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25DataUnitDetector.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DataUnitDetector.java similarity index 88% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25DataUnitDetector.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DataUnitDetector.java index 3a2e59ec1..28d8f30d1 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25DataUnitDetector.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DataUnitDetector.java @@ -1,50 +1,53 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25; + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ +package io.github.dsheirer.module.decode.p25.phase1; 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.edac.BCH_63_16_11; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import io.github.dsheirer.sample.Listener; import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class P25DataUnitDetector implements Listener, ISyncDetectListener +public class P25P1DataUnitDetector implements Listener, ISyncDetectListener { - private final static Logger mLog = LoggerFactory.getLogger(P25DataUnitDetector.class); + private final static Logger mLog = LoggerFactory.getLogger(P25P1DataUnitDetector.class); private static final int DATA_UNIT_DIBIT_LENGTH = 57; //56 dibits plus 1 status symbol private static final int SYNC_DIBIT_LENGTH = 24; private static final int MAXIMUM_SYNC_MATCH_BIT_ERRORS = 9; - private P25SyncDetector mSyncDetector; + private P25P1SyncDetector mSyncDetector; private NIDDelayBuffer mDataUnitBuffer = new NIDDelayBuffer(); private DibitDelayBuffer mSyncDelayBuffer = new DibitDelayBuffer(DATA_UNIT_DIBIT_LENGTH - SYNC_DIBIT_LENGTH); - private IDataUnitDetectListener mDataUnitDetectListener; + private IP25P1DataUnitDetectListener mDataUnitDetectListener; private boolean mInitialSyncTestProcessed = false; private int mDibitsProcessed = 0; private BCH_63_16_11 mNIDDecoder = new BCH_63_16_11(); - private DataUnitID mPreviousDataUnitId = DataUnitID.TERMINATOR_DATA_UNIT; + private P25P1DataUnitID mPreviousDataUnitId = P25P1DataUnitID.TERMINATOR_DATA_UNIT; private int mNIDDetectionCount; - public P25DataUnitDetector(IDataUnitDetectListener dataUnitDetectListener, IPhaseLockedLoop phaseLockedLoop) + public P25P1DataUnitDetector(IP25P1DataUnitDetectListener dataUnitDetectListener, IPhaseLockedLoop phaseLockedLoop) { mDataUnitDetectListener = dataUnitDetectListener; - mSyncDetector = new P25SyncDetector(this, phaseLockedLoop); + mSyncDetector = new P25P1SyncDetector(this, phaseLockedLoop); } /** @@ -142,25 +145,25 @@ private void checkForNid(int bitErrorCount, boolean forcedCheck) (bitErrorCount + nidBitErrorCount), (mDibitsProcessed - DATA_UNIT_DIBIT_LENGTH), correctedNid); } } - else if(mPreviousDataUnitId == DataUnitID.LOGICAL_LINK_DATA_UNIT_1) + else if(mPreviousDataUnitId == P25P1DataUnitID.LOGICAL_LINK_DATA_UNIT_1) { //We have a good sync match, but the NID didn't pass error control and we're in the middle //of voice call, so treat this message as voice message, but set the previous duid to //terminator so we can end if there isn't a subsequent voice message - mDataUnitDetectListener.dataUnitDetected(DataUnitID.LOGICAL_LINK_DATA_UNIT_2, -1, + mDataUnitDetectListener.dataUnitDetected(P25P1DataUnitID.LOGICAL_LINK_DATA_UNIT_2, -1, (bitErrorCount + 64), (mDibitsProcessed - DATA_UNIT_DIBIT_LENGTH), new int[63]); - mPreviousDataUnitId = DataUnitID.TERMINATOR_DATA_UNIT; + mPreviousDataUnitId = P25P1DataUnitID.TERMINATOR_DATA_UNIT; } - else if(mPreviousDataUnitId == DataUnitID.LOGICAL_LINK_DATA_UNIT_2) + else if(mPreviousDataUnitId == P25P1DataUnitID.LOGICAL_LINK_DATA_UNIT_2) { //We have a good sync match, but the NID didn't pass error control and we're in the middle //of voice call, so treat this message as voice message, but set the previous duid to //terminator so we can end if there isn't a subsequent voice message - mDataUnitDetectListener.dataUnitDetected(DataUnitID.LOGICAL_LINK_DATA_UNIT_1, -1, + mDataUnitDetectListener.dataUnitDetected(P25P1DataUnitID.LOGICAL_LINK_DATA_UNIT_1, -1, (bitErrorCount + 64), (mDibitsProcessed - DATA_UNIT_DIBIT_LENGTH), new int[63]); - mPreviousDataUnitId = DataUnitID.TERMINATOR_DATA_UNIT; + mPreviousDataUnitId = P25P1DataUnitID.TERMINATOR_DATA_UNIT; } } } @@ -170,7 +173,7 @@ else if(mPreviousDataUnitId == DataUnitID.LOGICAL_LINK_DATA_UNIT_2) * @param nid in reverse bit order * @return */ - public DataUnitID getDataUnitID(int[] nid) + public P25P1DataUnitID getDataUnitID(int[] nid) { int duid = 0; @@ -194,7 +197,7 @@ public DataUnitID getDataUnitID(int[] nid) duid ^= 8; } - return DataUnitID.fromValue(duid); + return P25P1DataUnitID.fromValue(duid); } /** diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/reference/DataUnitID.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DataUnitID.java similarity index 80% rename from src/main/java/io/github/dsheirer/module/decode/p25/reference/DataUnitID.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DataUnitID.java index ef63a6e33..cd6a26bed 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/reference/DataUnitID.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DataUnitID.java @@ -1,24 +1,28 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25.reference; + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ +package io.github.dsheirer.module.decode.p25.phase1; /** * The Data Unit ID (DUID) is part of the Network ID (NID) field and indicates the type of message. */ -public enum DataUnitID +public enum P25P1DataUnitID { HEADER_DATA_UNIT(0, 648 + 10, true, "HDU "), UNKNOWN_1(1, -1, false, "UNK01"), @@ -53,7 +57,7 @@ public enum DataUnitID private boolean mTrailingStatusDibit; private String mLabel; - DataUnitID(int value, int length, boolean trailingStatusDibit, String label) + P25P1DataUnitID(int value, int length, boolean trailingStatusDibit, String label) { mValue = value; mMessageLength = length; @@ -96,7 +100,7 @@ public boolean hasTrailingStatusDibit() /** * Lookup the Data Unit ID from an integer value */ - public static DataUnitID fromValue(int value) + public static P25P1DataUnitID fromValue(int value) { switch(value) { diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25Decoder.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1Decoder.java similarity index 80% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25Decoder.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1Decoder.java index 35dc9068f..c143a8311 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25Decoder.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1Decoder.java @@ -1,19 +1,25 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25; + */ +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.dsp.symbol.Dibit; import io.github.dsheirer.dsp.symbol.DibitToByteBufferAssembler; @@ -29,22 +35,22 @@ import io.github.dsheirer.source.ISourceEventProvider; import io.github.dsheirer.source.SourceEvent; -public abstract class P25Decoder extends Decoder implements ISourceEventListener, ISourceEventProvider, +public abstract class P25P1Decoder extends Decoder implements ISourceEventListener, ISourceEventProvider, IReusableComplexBufferListener, Listener, IReusableByteBufferProvider { private double mSampleRate; private Broadcaster mDibitBroadcaster = new Broadcaster<>(); private DibitToByteBufferAssembler mByteBufferAssembler = new DibitToByteBufferAssembler(300); - private P25MessageProcessor mMessageProcessor; + private P25P1MessageProcessor mMessageProcessor; private Listener mSourceEventListener; private double mSymbolRate; - public P25Decoder(double symbolRate) + public P25P1Decoder(double symbolRate) { mSymbolRate = symbolRate; - mMessageProcessor = new P25MessageProcessor(); + mMessageProcessor = new P25P1MessageProcessor(); mMessageProcessor.setMessageListener(getMessageListener()); - mDibitBroadcaster.addListener(mByteBufferAssembler); + getDibitBroadcaster().addListener(mByteBufferAssembler); } /** @@ -181,7 +187,7 @@ public void broadcast(SourceEvent sourceEvent) @Override public Listener getReusableComplexBufferListener() { - return P25Decoder.this; + return P25P1Decoder.this; } /** @@ -208,7 +214,7 @@ public DecoderType getDecoderType() return DecoderType.P25_PHASE1; } - protected P25MessageProcessor getMessageProcessor() + protected P25P1MessageProcessor getMessageProcessor() { return mMessageProcessor; } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FM.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FM.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FM.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FM.java index 79e3be912..ed26772ef 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FM.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FM.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -17,7 +17,7 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25; +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.dsp.filter.FilterFactory; import io.github.dsheirer.dsp.filter.design.FilterDesignException; @@ -37,16 +37,16 @@ import java.util.HashMap; import java.util.Map; -public class P25DecoderC4FM extends P25Decoder +public class P25P1DecoderC4FM extends P25P1Decoder { - private final static Logger mLog = LoggerFactory.getLogger(P25DecoderC4FM.class); + private final static Logger mLog = LoggerFactory.getLogger(P25P1DecoderC4FM.class); protected static final float SAMPLE_COUNTER_GAIN = 0.3f; protected InterpolatingSampleBuffer mInterpolatingSampleBuffer; protected DQPSKDecisionDirectedDemodulator mQPSKDemodulator; protected CostasLoop mCostasLoop; protected AdaptivePLLGainMonitor mPLLGainMonitor; - protected P25MessageFramer2 mMessageFramer; + protected P25P1MessageFramer mMessageFramer; private ComplexFeedForwardGainControl mAGC = new ComplexFeedForwardGainControl(32); private Map mBasebandFilters = new HashMap<>(); private ComplexFIRFilter2 mBasebandFilter; @@ -55,7 +55,7 @@ public class P25DecoderC4FM extends P25Decoder * P25 Phase 1 - standard C4FM modulation decoder. Uses Differential QPSK decoding with a Costas PLL and a * decision-directed phase and timing error detector. */ - public P25DecoderC4FM() + public P25P1DecoderC4FM() { super(4800.0); setSampleRate(25000.0); @@ -80,7 +80,7 @@ public void setSampleRate(double sampleRate) //The Costas Loop receives symbol-inversion correction requests when detected. //The PLL gain monitor receives sync detect/loss signals from the message framer - mMessageFramer = new P25MessageFramer2(mCostasLoop, DecoderType.P25_PHASE1.getProtocol().getBitRate()); + mMessageFramer = new P25P1MessageFramer(mCostasLoop, DecoderType.P25_PHASE1.getProtocol().getBitRate()); mMessageFramer.setSyncDetectListener(mPLLGainMonitor); mMessageFramer.setListener(getMessageProcessor()); mMessageFramer.setSampleRate(sampleRate); diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FMInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FMInstrumented.java similarity index 83% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FMInstrumented.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FMInstrumented.java index 6c92fc60b..8b7438c97 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderC4FMInstrumented.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderC4FMInstrumented.java @@ -1,19 +1,23 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25; + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.dsp.psk.DQPSKDecisionDirectedDemodulatorInstrumented; import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented; @@ -22,7 +26,7 @@ import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.Complex; -public class P25DecoderC4FMInstrumented extends P25DecoderC4FM +public class P25P1DecoderC4FMInstrumented extends P25P1DecoderC4FM { private Listener mPLLPhaseErrorListener; private Listener mPLLFrequencyListener; @@ -35,7 +39,7 @@ public class P25DecoderC4FMInstrumented extends P25DecoderC4FM * Instrumented version of the P25 C4FM decoder that supports registering listeners to provide access to data as * it is being processed by the decoder. */ - public P25DecoderC4FMInstrumented() + public P25P1DecoderC4FMInstrumented() { } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderEditor.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderEditor.java similarity index 92% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderEditor.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderEditor.java index 967a0b790..c26a31525 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderEditor.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderEditor.java @@ -17,7 +17,7 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25; +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.controller.channel.Channel; import io.github.dsheirer.gui.editor.Editor; @@ -44,18 +44,18 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -public class P25DecoderEditor extends ValidatingEditor +public class P25P1DecoderEditor extends ValidatingEditor { - private final static Logger mLog = LoggerFactory.getLogger(P25DecoderEditor.class); + private final static Logger mLog = LoggerFactory.getLogger(P25P1DecoderEditor.class); private static final long serialVersionUID = 1L; - private JComboBox mComboModulation; + private JComboBox mComboModulation; private JCheckBox mIgnoreDataCalls; private JLabel mTrafficChannelPoolSizeLabel; private JSlider mTrafficChannelPoolSize; - public P25DecoderEditor() + public P25P1DecoderEditor() { init(); } @@ -64,9 +64,9 @@ private void init() { setLayout(new MigLayout("insets 0 0 0 0,wrap 3", "[right][grow,fill][]", "")); - mComboModulation = new JComboBox(); - mComboModulation.setModel(new DefaultComboBoxModel( - P25DecoderLSM.Modulation.values())); + mComboModulation = new JComboBox(); + mComboModulation.setModel(new DefaultComboBoxModel( + P25P1DecoderLSM.Modulation.values())); mComboModulation.setEnabled(false); mComboModulation.addActionListener(new ActionListener() { @@ -122,7 +122,7 @@ public void save() { DecodeConfigP25Phase1 p25 = new DecodeConfigP25Phase1(); - p25.setModulation((P25Decoder.Modulation)mComboModulation.getSelectedItem()); + p25.setModulation((P25P1Decoder.Modulation)mComboModulation.getSelectedItem()); p25.setIgnoreDataCalls(mIgnoreDataCalls.isSelected()); p25.setTrafficChannelPoolSize(mTrafficChannelPoolSize.getValue()); @@ -206,7 +206,7 @@ public void setItem(Channel item) } else { - mComboModulation.setSelectedItem(P25Decoder.Modulation.C4FM); + mComboModulation.setSelectedItem(P25P1Decoder.Modulation.C4FM); mIgnoreDataCalls.setSelected(false); mTrafficChannelPoolSize.setValue(DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT); setModified(true); diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSM.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSM.java similarity index 66% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSM.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSM.java index 101971d68..e03a115ed 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSM.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSM.java @@ -1,23 +1,25 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25; +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.dsp.filter.FilterFactory; import io.github.dsheirer.dsp.filter.Window.WindowType; @@ -28,15 +30,23 @@ import io.github.dsheirer.dsp.psk.pll.AdaptivePLLGainMonitor; import io.github.dsheirer.dsp.psk.pll.CostasLoop; import io.github.dsheirer.module.decode.DecoderType; +import io.github.dsheirer.protocol.Protocol; +import io.github.dsheirer.record.binary.BinaryRecorder; import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.source.SourceEvent; +import io.github.dsheirer.source.wave.ComplexWaveSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; -public class P25DecoderLSM extends P25Decoder +public class P25P1DecoderLSM extends P25P1Decoder { -// private final static Logger mLog = LoggerFactory.getLogger(P25DecoderLSM.class); + private final static Logger mLog = LoggerFactory.getLogger(P25P1DecoderLSM.class); protected static final float SAMPLE_COUNTER_GAIN = 0.3f; @@ -44,7 +54,7 @@ public class P25DecoderLSM extends P25Decoder private ComplexFIRFilter2 mBasebandFilter; private ComplexFeedForwardGainControl mAGC = new ComplexFeedForwardGainControl(32); protected DQPSKGardnerDemodulator mQPSKDemodulator; - protected P25MessageFramer2 mMessageFramer; + protected P25P1MessageFramer mMessageFramer; protected CostasLoop mCostasLoop; protected AdaptivePLLGainMonitor mPLLGainMonitor; protected InterpolatingSampleBuffer mInterpolatingSampleBuffer; @@ -53,7 +63,7 @@ public class P25DecoderLSM extends P25Decoder * P25 Phase 1 - linear simulcast modulation (LSM) decoder. Uses Differential QPSK decoding with a Costas PLL and * a gardner timing error detector. */ - public P25DecoderLSM() + public P25P1DecoderLSM() { super(4800.0); setSampleRate(25000.0); @@ -84,7 +94,7 @@ public void setSampleRate(double sampleRate) getDibitBroadcaster().removeListener(mMessageFramer); } - mMessageFramer = new P25MessageFramer2(mCostasLoop, DecoderType.P25_PHASE1.getProtocol().getBitRate()); + mMessageFramer = new P25P1MessageFramer(mCostasLoop, DecoderType.P25_PHASE1.getProtocol().getBitRate()); mMessageFramer.setSyncDetectListener(mPLLGainMonitor); mMessageFramer.setListener(getMessageProcessor()); mMessageFramer.setSampleRate(sampleRate); @@ -195,4 +205,44 @@ private float[] getBasebandFilter() return filter; } + + public static void main(String[] args) + { + String path = "/media/denny/500G1EXT4/RadioRecordings/"; +// String input = "DFWAirport_Site_857_3875_baseband_20181213_223236.wav"; +// String output = "DFWAirport_Site_857_3875_baseband_20181213_223236"; + + String input = "P25P2_HCPM_Metrocrest_Dallas_857_7625_phase_2_not_motorola_baseband_20181213_224616_control_channel.wav"; + String output = "P25P2_HCPM_Metrocrest_Dallas_857_7625_phase_2_not_motorola_baseband_20181213_224616_control_channel"; + + + P25P1DecoderLSM decoder = new P25P1DecoderLSM(); + BinaryRecorder recorder = new BinaryRecorder(Path.of(path), output, Protocol.APCO25); + decoder.setBufferListener(recorder.getReusableByteBufferListener()); + recorder.start(); + + File file = new File(path + input); + + boolean running = true; + + try(ComplexWaveSource source = new ComplexWaveSource(file)) + { + decoder.setSampleRate(50000.0); + source.setListener(decoder); + source.start(); + + while(running) + { + source.next(200, true); + } + } + catch(IOException e) + { + mLog.error("Error", e); + running = false; + } + + recorder.stop(); + } + } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSMInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSMInstrumented.java similarity index 83% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSMInstrumented.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSMInstrumented.java index ea56c1503..0c4ad986b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderLSMInstrumented.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderLSMInstrumented.java @@ -1,19 +1,23 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25; + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.dsp.psk.DQPSKGardnerDemodulatorInstrumented; import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented; @@ -22,7 +26,7 @@ import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; import io.github.dsheirer.sample.complex.Complex; -public class P25DecoderLSMInstrumented extends P25DecoderLSM +public class P25P1DecoderLSMInstrumented extends P25P1DecoderLSM { private Listener mPLLPhaseErrorListener; private Listener mPLLFrequencyListener; @@ -37,7 +41,7 @@ public class P25DecoderLSMInstrumented extends P25DecoderLSM * * Instrumented decoder instance. */ - public P25DecoderLSMInstrumented() + public P25P1DecoderLSMInstrumented() { } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderState.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderState.java similarity index 88% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderState.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderState.java index 714d20192..ab7c47e7b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25DecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderState.java @@ -1,23 +1,25 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25; +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.channel.state.ChangeChannelTimeoutEvent; import io.github.dsheirer.channel.state.DecoderState; @@ -43,90 +45,94 @@ import io.github.dsheirer.module.decode.ip.ars.ARSPacket; import io.github.dsheirer.module.decode.ip.ipv4.IPV4Packet; import io.github.dsheirer.module.decode.ip.udp.UDPPacket; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.message.hdu.HDUMessage; -import io.github.dsheirer.module.decode.p25.message.hdu.HeaderData; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCCallTermination; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCExtendedFunctionCommand; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCMessageUpdate; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCStatusUpdate; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCTelephoneInterconnectAnswerRequest; -import io.github.dsheirer.module.decode.p25.message.ldu.EncryptionSyncParameters; -import io.github.dsheirer.module.decode.p25.message.ldu.LDU1Message; -import io.github.dsheirer.module.decode.p25.message.ldu.LDU2Message; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCAuthenticationResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCIndividualDataServiceRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCLocationRegistrationRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCMessageUpdateRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCStatusQueryResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCStatusUpdateRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCUnitAcknowledgeResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCUnitToUnitVoiceServiceAnswerResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCUnitToUnitVoiceServiceRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCGroupAffiliationResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCGroupDataChannelGrant; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCGroupVoiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCIndividualDataChannelGrant; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCMessageUpdate; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCProtectionParameterBroadcast; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCStatusUpdate; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCTelephoneInterconnectChannelGrant; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCTelephoneInterconnectChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCUnitRegistrationResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCUnitToUnitVoiceServiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCUnitToUnitVoiceServiceChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.message.pdu.packet.PacketMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp.SNDCPMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp.SNDCPPacketMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.umbtc.isp.UMBTCTelephoneInterconnectRequestExplicitDialing; -import io.github.dsheirer.module.decode.p25.message.tdu.TDULinkControlMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.TSBKMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.MotorolaDenyResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.CancelServiceRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.ExtendedFunctionResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.GroupAffiliationQueryResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.GroupDataServiceRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.GroupVoiceServiceRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.IndividualDataServiceRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.LocationRegistrationRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.MessageUpdateRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.SNDCPDataChannelRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.SNDCPDataPageResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.SNDCPReconnectRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.StatusQueryResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.StatusUpdateRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.TelephoneInterconnectAnswerResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitAcknowledgeResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitRegistrationRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitToUnitVoiceServiceAnswerResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitToUnitVoiceServiceRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.AcknowledgeResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.DenyResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.ExtendedFunctionCommand; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupAffiliationResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupDataChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupVoiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupVoiceChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupVoiceChannelGrantUpdateExplicit; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.LocationRegistrationResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.MessageUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.QueuedResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.RoamingAddressCommand; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SNDCPDataChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.StatusUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.TelephoneInterconnectAnswerRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.TelephoneInterconnectVoiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.TelephoneInterconnectVoiceChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnitRegistrationResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.network.P25NetworkConfigurationMonitor; +import io.github.dsheirer.module.decode.p25.P25DecodeEvent; +import io.github.dsheirer.module.decode.p25.P25TrafficChannelManager; +import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; +import io.github.dsheirer.module.decode.p25.phase1.message.P25Message; +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.module.decode.p25.phase1.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCCallTermination; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCExtendedFunctionCommand; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCMessageUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCStatusUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCTelephoneInterconnectAnswerRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.ldu.EncryptionSyncParameters; +import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU1Message; +import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU2Message; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCAuthenticationResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCIndividualDataServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCLocationRegistrationRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCMessageUpdateRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCStatusQueryResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCStatusUpdateRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCUnitAcknowledgeResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCUnitToUnitVoiceServiceAnswerResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCUnitToUnitVoiceServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCGroupAffiliationResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCGroupDataChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCGroupVoiceChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCIndividualDataChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCMessageUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCProtectionParameterBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCStatusUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCTelephoneInterconnectChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCTelephoneInterconnectChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCUnitRegistrationResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCUnitToUnitVoiceServiceChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCUnitToUnitVoiceServiceChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.PacketMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPPacketMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.umbtc.isp.UMBTCTelephoneInterconnectRequestExplicitDialing; +import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDULinkControlMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.TSBKMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.MotorolaDenyResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.CancelServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.ExtendedFunctionResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.GroupAffiliationQueryResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.GroupDataServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.GroupVoiceServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.IndividualDataServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.LocationRegistrationRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.MessageUpdateRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.SNDCPDataChannelRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.SNDCPDataPageResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.SNDCPReconnectRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.StatusQueryResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.StatusUpdateRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.TelephoneInterconnectAnswerResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitAcknowledgeResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitRegistrationRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitToUnitVoiceServiceAnswerResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitToUnitVoiceServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.AcknowledgeResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.DenyResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.ExtendedFunctionCommand; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupAffiliationResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupDataChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupVoiceChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupVoiceChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupVoiceChannelGrantUpdateExplicit; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.LocationRegistrationResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.MessageUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.QueuedResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.RoamingAddressCommand; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SNDCPDataChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.StatusUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.TelephoneInterconnectAnswerRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.TelephoneInterconnectVoiceChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.TelephoneInterconnectVoiceChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitRegistrationResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrantUpdate; import io.github.dsheirer.module.decode.p25.reference.Encryption; +import io.github.dsheirer.module.decode.p25.reference.ServiceOptions; import io.github.dsheirer.sample.Listener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -136,14 +142,14 @@ * monitoring the decoded message stream. * */ -public class P25DecoderState extends DecoderState implements IChannelEventListener +public class P25P1DecoderState extends DecoderState implements IChannelEventListener { - private final static Logger mLog = LoggerFactory.getLogger(P25DecoderState.class); + private final static Logger mLog = LoggerFactory.getLogger(P25P1DecoderState.class); private ChannelType mChannelType; - private P25Decoder.Modulation mModulation; + private P25P1Decoder.Modulation mModulation; private PatchGroupManager mPatchGroupManager = new PatchGroupManager(); - private P25NetworkConfigurationMonitor mNetworkConfigurationMonitor; + private P25P1NetworkConfigurationMonitor mNetworkConfigurationMonitor; private P25TrafficChannelManager mTrafficChannelManager; private Listener mChannelEventListener; private DecodeEvent mCurrentCallEvent; @@ -153,11 +159,11 @@ public class P25DecoderState extends DecoderState implements IChannelEventListen * @param channel with configuration details * @param trafficChannelManager for handling traffic channel grants. */ - public P25DecoderState(Channel channel, P25TrafficChannelManager trafficChannelManager) + public P25P1DecoderState(Channel channel, P25TrafficChannelManager trafficChannelManager) { mChannelType = channel.getChannelType(); mModulation = ((DecodeConfigP25Phase1)channel.getDecodeConfiguration()).getModulation(); - mNetworkConfigurationMonitor = new P25NetworkConfigurationMonitor(mModulation); + mNetworkConfigurationMonitor = new P25P1NetworkConfigurationMonitor(mModulation); if(trafficChannelManager != null) { @@ -176,7 +182,7 @@ public P25DecoderState(Channel channel, P25TrafficChannelManager trafficChannelM * Constructs an APCO-25 decoder state for a traffic channel. * @param channel with configuration details */ - public P25DecoderState(Channel channel) + public P25P1DecoderState(Channel channel) { this(channel, null); } @@ -184,7 +190,7 @@ public P25DecoderState(Channel channel) /** * Modulation type for the decoder */ - public P25Decoder.Modulation getModulation() + public P25P1Decoder.Modulation getModulation() { return mModulation; } @@ -214,6 +220,7 @@ public Listener getChannelEventListener() @Override public void reset() { + super.reset(); resetState(); } @@ -285,6 +292,25 @@ public void receive(IMessage iMessage) } } + /** + * Commands the traffic channel manager to process a traffic channel grant and allocate a decoder + * to process the traffic channel. + * @param apco25Channel to allocate + * @param serviceOptions for the channel + * @param identifierCollection identifying the users of the channel + * @param opcode that identifies the type of channel grant + * @param timestamp when the channel grant occurred. + */ + private void processChannelGrant(APCO25Channel apco25Channel, ServiceOptions serviceOptions, + IdentifierCollection identifierCollection, Opcode opcode, long timestamp) + { + if(mTrafficChannelManager != null && apco25Channel.getValue().getFrequencyBand() != null) + { + mTrafficChannelManager.processChannelGrant(apco25Channel, serviceOptions, identifierCollection, opcode, + timestamp); + } + } + /** * Alternate Multi-Block Trunking Control (AMBTC) * @@ -504,6 +530,12 @@ private void processAMBTC(P25Message message) case OSP_ADJACENT_STATUS_BROADCAST: mNetworkConfigurationMonitor.process(ambtc); break; + case OSP_NETWORK_STATUS_BROADCAST: + mNetworkConfigurationMonitor.process(ambtc); + break; + case OSP_RFSS_STATUS_BROADCAST: + mNetworkConfigurationMonitor.process(ambtc); + break; //Channel grants case OSP_GROUP_DATA_CHANNEL_GRANT: @@ -511,16 +543,12 @@ private void processAMBTC(P25Message message) { AMBTCGroupDataChannelGrant gdcg = (AMBTCGroupDataChannelGrant)ambtc; - if(mTrafficChannelManager != null) - { - MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); - identifierCollection.remove(IdentifierClass.USER); - identifierCollection.update(gdcg.getIdentifiers()); - - mTrafficChannelManager.processChannelGrant(gdcg.getChannel(), gdcg.getDataServiceOptions(), + MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + identifierCollection.remove(IdentifierClass.USER); + identifierCollection.update(gdcg.getIdentifiers()); + processChannelGrant(gdcg.getChannel(), gdcg.getDataServiceOptions(), identifierCollection, ambtc.getHeader().getOpcode(), ambtc.getTimestamp()); - } } break; case OSP_GROUP_VOICE_CHANNEL_GRANT: @@ -532,12 +560,9 @@ private void processAMBTC(P25Message message) identifierCollection.remove(IdentifierClass.USER); identifierCollection.update(gvcg.getIdentifiers()); - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(gvcg.getChannel(), gvcg.getVoiceServiceOptions(), + processChannelGrant(gvcg.getChannel(), gvcg.getVoiceServiceOptions(), identifierCollection, ambtc.getHeader().getOpcode(), ambtc.getTimestamp()); - } } break; case OSP_INDIVIDUAL_DATA_CHANNEL_GRANT: @@ -549,12 +574,9 @@ private void processAMBTC(P25Message message) identifierCollection.remove(IdentifierClass.USER); identifierCollection.update(idcg.getIdentifiers()); - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(idcg.getChannel(), idcg.getDataServiceOptions(), + processChannelGrant(idcg.getChannel(), idcg.getDataServiceOptions(), identifierCollection, ambtc.getHeader().getOpcode(), ambtc.getTimestamp()); - } } break; case OSP_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT: @@ -562,16 +584,13 @@ private void processAMBTC(P25Message message) { AMBTCTelephoneInterconnectChannelGrant ticg = (AMBTCTelephoneInterconnectChannelGrant)ambtc; - if(mTrafficChannelManager != null) - { - MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); - identifierCollection.remove(IdentifierClass.USER); - identifierCollection.update(ticg.getIdentifiers()); + MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + identifierCollection.remove(IdentifierClass.USER); + identifierCollection.update(ticg.getIdentifiers()); - mTrafficChannelManager.processChannelGrant(ticg.getChannel(), ticg.getVoiceServiceOptions(), + processChannelGrant(ticg.getChannel(), ticg.getVoiceServiceOptions(), identifierCollection, ambtc.getHeader().getOpcode(), ambtc.getTimestamp()); - } } break; case OSP_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE: @@ -579,16 +598,13 @@ private void processAMBTC(P25Message message) { AMBTCTelephoneInterconnectChannelGrantUpdate ticgu = (AMBTCTelephoneInterconnectChannelGrantUpdate)ambtc; - if(mTrafficChannelManager != null) - { - MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); - identifierCollection.remove(IdentifierClass.USER); - identifierCollection.update(ticgu.getIdentifiers()); + MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + identifierCollection.remove(IdentifierClass.USER); + identifierCollection.update(ticgu.getIdentifiers()); - mTrafficChannelManager.processChannelGrant(ticgu.getChannel(), ticgu.getVoiceServiceOptions(), + processChannelGrant(ticgu.getChannel(), ticgu.getVoiceServiceOptions(), identifierCollection, ambtc.getHeader().getOpcode(), ambtc.getTimestamp()); - } } break; case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT: @@ -596,16 +612,13 @@ private void processAMBTC(P25Message message) { AMBTCUnitToUnitVoiceServiceChannelGrant uuvscg = (AMBTCUnitToUnitVoiceServiceChannelGrant)ambtc; - if(mTrafficChannelManager != null) - { - MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); - identifierCollection.remove(IdentifierClass.USER); - identifierCollection.update(uuvscg.getIdentifiers()); + MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + identifierCollection.remove(IdentifierClass.USER); + identifierCollection.update(uuvscg.getIdentifiers()); - mTrafficChannelManager.processChannelGrant(uuvscg.getChannel(), uuvscg.getVoiceServiceOptions(), + processChannelGrant(uuvscg.getChannel(), uuvscg.getVoiceServiceOptions(), identifierCollection, ambtc.getHeader().getOpcode(), ambtc.getTimestamp()); - } } break; case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE: @@ -613,16 +626,13 @@ private void processAMBTC(P25Message message) { AMBTCUnitToUnitVoiceServiceChannelGrantUpdate uuvscgu = (AMBTCUnitToUnitVoiceServiceChannelGrantUpdate)ambtc; - if(mTrafficChannelManager != null) - { - MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); - identifierCollection.remove(IdentifierClass.USER); - identifierCollection.update(uuvscgu.getIdentifiers()); + MutableIdentifierCollection identifierCollection = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + identifierCollection.remove(IdentifierClass.USER); + identifierCollection.update(uuvscgu.getIdentifiers()); - mTrafficChannelManager.processChannelGrant(uuvscgu.getChannel(), uuvscgu.getVoiceServiceOptions(), + processChannelGrant(uuvscgu.getChannel(), uuvscgu.getVoiceServiceOptions(), identifierCollection, ambtc.getHeader().getOpcode(), ambtc.getTimestamp()); - } } break; case OSP_UNIT_TO_UNIT_ANSWER_REQUEST: @@ -1171,11 +1181,8 @@ private void processTSBK(P25Message message) identifiers.update(mPatchGroupManager.update(identifier)); } - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(gdcg.getChannel(), gdcg.getDataServiceOptions(), + processChannelGrant(gdcg.getChannel(), gdcg.getDataServiceOptions(), identifiers, tsbk.getOpcode(), gdcg.getTimestamp()); - } } break; case OSP_GROUP_VOICE_CHANNEL_GRANT: @@ -1191,11 +1198,8 @@ private void processTSBK(P25Message message) identifiers.update(mPatchGroupManager.update(identifier)); } - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(gvcg.getChannel(), gvcg.getVoiceServiceOptions(), + processChannelGrant(gvcg.getChannel(), gvcg.getVoiceServiceOptions(), identifiers, tsbk.getOpcode(), gvcg.getTimestamp()); - } } break; case OSP_GROUP_VOICE_CHANNEL_GRANT_UPDATE: @@ -1208,11 +1212,8 @@ private void processTSBK(P25Message message) identifiersA.remove(IdentifierClass.USER); identifiersA.update(mPatchGroupManager.update(gvcgu.getGroupAddressA())); - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(gvcgu.getChannelA(), null, identifiersA, + processChannelGrant(gvcgu.getChannelA(), null, identifiersA, tsbk.getOpcode(), gvcgu.getTimestamp()); - } if(gvcgu.hasGroupB()) { @@ -1221,11 +1222,8 @@ private void processTSBK(P25Message message) identifiersB.remove(IdentifierClass.USER); identifiersB.update(mPatchGroupManager.update(gvcgu.getGroupAddressB())); - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(gvcgu.getChannelB(), null, identifiersB, + processChannelGrant(gvcgu.getChannelB(), null, identifiersB, tsbk.getOpcode(), gvcgu.getTimestamp()); - } } } break; @@ -1239,11 +1237,8 @@ private void processTSBK(P25Message message) identifiers.remove(IdentifierClass.USER); identifiers.update(mPatchGroupManager.update(gvcgue.getGroupAddress())); - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(gvcgue.getChannel(), gvcgue.getVoiceServiceOptions(), + processChannelGrant(gvcgue.getChannel(), gvcgue.getVoiceServiceOptions(), identifiers, tsbk.getOpcode(), gvcgue.getTimestamp()); - } } break; case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT: @@ -1256,11 +1251,8 @@ private void processTSBK(P25Message message) identifiers.remove(IdentifierClass.USER); identifiers.update(uuvcg.getIdentifiers()); - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(uuvcg.getChannel(), null, identifiers, + processChannelGrant(uuvcg.getChannel(), null, identifiers, tsbk.getOpcode(), uuvcg.getTimestamp()); - } } break; case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE: @@ -1273,11 +1265,8 @@ private void processTSBK(P25Message message) identifiers.remove(IdentifierClass.USER); identifiers.update(uuvcgu.getIdentifiers()); - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(uuvcgu.getChannel(), null, identifiers, + processChannelGrant(uuvcgu.getChannel(), null, identifiers, tsbk.getOpcode(), uuvcgu.getTimestamp()); - } } break; case OSP_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT: @@ -1290,11 +1279,8 @@ private void processTSBK(P25Message message) identifiers.remove(IdentifierClass.USER); identifiers.update(tivcg.getIdentifiers()); - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(tivcg.getChannel(), tivcg.getVoiceServiceOptions(), + processChannelGrant(tivcg.getChannel(), tivcg.getVoiceServiceOptions(), identifiers, tsbk.getOpcode(), tivcg.getTimestamp()); - } } break; case OSP_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT_UPDATE: @@ -1307,11 +1293,8 @@ private void processTSBK(P25Message message) identifiers.remove(IdentifierClass.USER); identifiers.update(tivcgu.getIdentifiers()); - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(tivcgu.getChannel(), tivcgu.getVoiceServiceOptions(), + processChannelGrant(tivcgu.getChannel(), tivcgu.getVoiceServiceOptions(), identifiers, tsbk.getOpcode(), tivcgu.getTimestamp()); - } } break; case OSP_SNDCP_DATA_CHANNEL_GRANT: @@ -1324,11 +1307,8 @@ private void processTSBK(P25Message message) identifiers.remove(IdentifierClass.USER); identifiers.update(dcg.getIdentifiers()); - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(dcg.getChannel(), dcg.getServiceOptions(), + processChannelGrant(dcg.getChannel(), dcg.getServiceOptions(), identifiers, tsbk.getOpcode(), dcg.getTimestamp()); - } } break; case MOTOROLA_OSP_PATCH_GROUP_CHANNEL_GRANT: @@ -1344,11 +1324,8 @@ private void processTSBK(P25Message message) identifiers.update(mPatchGroupManager.update(identifier)); } - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(pgvcg.getChannel(), pgvcg.getVoiceServiceOptions(), + processChannelGrant(pgvcg.getChannel(), pgvcg.getVoiceServiceOptions(), identifiers, tsbk.getOpcode(), pgvcg.getTimestamp()); - } } break; case MOTOROLA_OSP_PATCH_GROUP_CHANNEL_GRANT_UPDATE: @@ -1361,11 +1338,8 @@ private void processTSBK(P25Message message) identifiersPG1.remove(IdentifierClass.USER); identifiersPG1.update(mPatchGroupManager.update(pgvcgu.getPatchGroup1())); - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(pgvcgu.getChannel1(), null, identifiersPG1, + processChannelGrant(pgvcgu.getChannel1(), null, identifiersPG1, tsbk.getOpcode(), pgvcgu.getTimestamp()); - } if(pgvcgu.hasPatchGroup2()) { @@ -1374,11 +1348,8 @@ private void processTSBK(P25Message message) identifiersPG2.remove(IdentifierClass.USER); identifiersPG2.update(mPatchGroupManager.update(pgvcgu.getPatchGroup2())); - if(mTrafficChannelManager != null) - { - mTrafficChannelManager.processChannelGrant(pgvcgu.getChannel2(), null, + processChannelGrant(pgvcgu.getChannel2(), null, identifiersPG2, tsbk.getOpcode(), pgvcgu.getTimestamp()); - } } } break; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25Interleave.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1Interleave.java similarity index 88% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25Interleave.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1Interleave.java index 37e73c01e..fe1cbe38d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25Interleave.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1Interleave.java @@ -1,4 +1,24 @@ -package io.github.dsheirer.module.decode.p25; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.bits.CorrectedBinaryMessage; @@ -10,10 +30,10 @@ /** * Utility class to process interleave of P25 Voice and Data messages. */ -public class P25Interleave +public class P25P1Interleave { private final static Logger mLog = - LoggerFactory.getLogger(P25Interleave.class); + LoggerFactory.getLogger(P25P1Interleave.class); public static int[] DATA_INTERLEAVE = new int[]{0, 1, 2, 3, 52, 53, 54, 55, 100, 101, 102, 103, 148, 149, 150, 151, 4, 5, 6, 7, 56, 57, 58, 59, 104, 105, 106, 107, 152, 153, diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25MessageFramer2.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageFramer.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25MessageFramer2.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageFramer.java index 242f23ace..d660ed295 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25MessageFramer2.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageFramer.java @@ -1,43 +1,43 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25; +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.bits.BitSetFullException; import io.github.dsheirer.bits.CorrectedBinaryMessage; 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.SyncLossMessage; import io.github.dsheirer.module.decode.DecoderType; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.message.P25MessageFactory; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUMessageFactory; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.umbtc.UMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.TSBKMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.TSBKMessageFactory; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.audio.P25P1CallSequenceRecorder; +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.pdu.PDUMessageFactory; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.TSBKMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.TSBKMessageFactory; +import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.protocol.Protocol; import io.github.dsheirer.record.binary.BinaryReader; import io.github.dsheirer.sample.Listener; @@ -52,17 +52,17 @@ * P25 Sync Detector and Message Framer. Includes capability to detect PLL out-of-phase lock errors * and issue phase corrections. */ -public class P25MessageFramer2 implements Listener, IDataUnitDetectListener +public class P25P1MessageFramer implements Listener, IP25P1DataUnitDetectListener { - private final static Logger mLog = LoggerFactory.getLogger(P25MessageFramer2.class); + private final static Logger mLog = LoggerFactory.getLogger(P25P1MessageFramer.class); - private P25DataUnitDetector mDataUnitDetector; - private P25ChannelStatusProcessor mChannelStatusProcessor = new P25ChannelStatusProcessor(); + private P25P1DataUnitDetector mDataUnitDetector; + private P25P1ChannelStatusProcessor mChannelStatusProcessor = new P25P1ChannelStatusProcessor(); private Listener mMessageListener; private boolean mAssemblingMessage = false; private CorrectedBinaryMessage mBinaryMessage; - private DataUnitID mDataUnitID; + private P25P1DataUnitID mDataUnitID; private PDUSequence mPDUSequence; private int[] mCorrectedNID; private int mNAC; @@ -72,13 +72,13 @@ public class P25MessageFramer2 implements Listener, IDataUnitDetectListen private long mCurrentTime = System.currentTimeMillis(); private ISyncDetectListener mSyncDetectListener; - public P25MessageFramer2(IPhaseLockedLoop phaseLockedLoop, int bitRate) + public P25P1MessageFramer(IPhaseLockedLoop phaseLockedLoop, int bitRate) { - mDataUnitDetector = new P25DataUnitDetector(this, phaseLockedLoop); + mDataUnitDetector = new P25P1DataUnitDetector(this, phaseLockedLoop); mBitRate = bitRate; } - public P25MessageFramer2(int bitRate) + public P25P1MessageFramer(int bitRate) { this(null, bitRate); } @@ -144,7 +144,7 @@ public void setListener(Listener messageListener) mMessageListener = messageListener; } - public P25DataUnitDetector getDataUnitDetector() + public P25P1DataUnitDetector getDataUnitDetector() { return mDataUnitDetector; } @@ -227,8 +227,8 @@ private void dispatchMessage() mPDUSequence.getHeader().getBlocksToFollowCount() > 0) { //Setup to catch the sequence of data blocks that follow the header - mDataUnitID = DataUnitID.PACKET_DATA_UNIT; - mBinaryMessage = new CorrectedBinaryMessage(DataUnitID.PACKET_DATA_UNIT.getMessageLength()); + mDataUnitID = P25P1DataUnitID.PACKET_DATA_UNIT; + mBinaryMessage = new CorrectedBinaryMessage(P25P1DataUnitID.PACKET_DATA_UNIT.getMessageLength()); mAssemblingMessage = true; } else @@ -291,8 +291,8 @@ private void dispatchMessage() else { //Setup to catch the next data block - mDataUnitID = DataUnitID.PACKET_DATA_UNIT; - mBinaryMessage = new CorrectedBinaryMessage(DataUnitID.PACKET_DATA_UNIT.getMessageLength()); + mDataUnitID = P25P1DataUnitID.PACKET_DATA_UNIT; + mBinaryMessage = new CorrectedBinaryMessage(P25P1DataUnitID.PACKET_DATA_UNIT.getMessageLength()); mAssemblingMessage = true; } } @@ -319,13 +319,13 @@ private void dispatchMessage() { updateBitsProcessed(mDataUnitID.getMessageLength()); mBinaryMessage = new CorrectedBinaryMessage(mDataUnitID.getMessageLength()); - if(mDataUnitID == DataUnitID.TRUNKING_SIGNALING_BLOCK_1) + if(mDataUnitID == P25P1DataUnitID.TRUNKING_SIGNALING_BLOCK_1) { - mDataUnitID = DataUnitID.TRUNKING_SIGNALING_BLOCK_2; + mDataUnitID = P25P1DataUnitID.TRUNKING_SIGNALING_BLOCK_2; } - else if(mDataUnitID == DataUnitID.TRUNKING_SIGNALING_BLOCK_2) + else if(mDataUnitID == P25P1DataUnitID.TRUNKING_SIGNALING_BLOCK_2) { - mDataUnitID = DataUnitID.TRUNKING_SIGNALING_BLOCK_3; + mDataUnitID = P25P1DataUnitID.TRUNKING_SIGNALING_BLOCK_3; } } break; @@ -376,7 +376,7 @@ public void receive(ReusableByteBuffer buffer) } @Override - public void dataUnitDetected(DataUnitID dataUnitID, int nac, int bitErrors, int discardedDibits, int[] correctedNid) + public void dataUnitDetected(P25P1DataUnitID dataUnitID, int nac, int bitErrors, int discardedDibits, int[] correctedNid) { if(discardedDibits > 0) { @@ -428,74 +428,38 @@ private void dispatchSyncLoss(int bitsProcessed) public static void main(String[] args) { - boolean pduOnly = false; - boolean mbtcOnly = false; - boolean sndcpOnly = false; - boolean ippacketOnly = false; - boolean patchOnly = false; - - P25MessageFramer2 messageFramer = new P25MessageFramer2(null, DecoderType.P25_PHASE1.getProtocol().getBitRate()); - messageFramer.setListener(new Listener() - { - @Override - public void receive(Message message) - { - if(mbtcOnly) - { - if(message instanceof AMBTCMessage || message instanceof UMBTCMessage) - { - mLog.debug(message.toString()); - } - } - else if(pduOnly) - { - String s = message.toString(); + P25P1DecoderLSM decoderLSM = new P25P1DecoderLSM(); - if(s.contains(" PDU ")) - { - mLog.debug(s); - } - } - else if(sndcpOnly) - { - String s = message.toString(); - if(s.contains("SNDCP")) - { - mLog.debug(s); - } - } - else if(ippacketOnly) - { - String s = message.toString(); +// Path path = Paths.get("/media/denny/500G1EXT4/RadioRecordings/APCO25P2/DFW Airport Encrypted/20190719_073751_9600BPS_APCO25PHASE1_DFWAirport_Site_857_3875_baseband_20181213_223236.bits"); + Path path = Paths.get("/media/denny/500G1EXT4/RadioRecordings/20190720_071117_9600BPS_APCO25PHASE1_P25P2_HCPM_Metrocrest_Dallas_857_7625_phase_2_not_motorola_baseband_20181213_224616_control_channel.bits"); - if(s.contains("IPPKT") || s.contains("SNDCP") || s.contains(" PDU ")) - { - mLog.debug(s); - } - } - else if(patchOnly) - { - if(message instanceof PatchGroupVoiceChannelGrant || message instanceof PatchGroupVoiceChannelGrantUpdate) - { - mLog.debug(message.toString()); - } - } - else - { - String a = message.toString(); - mLog.debug(a); - } - } - }); + P25P1MessageFramer messageFramer = new P25P1MessageFramer(null, DecoderType.P25_PHASE1.getProtocol().getBitRate()); -// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181102_102339_9600BPS_CNYICC_Onondaga Simulcast_LCN 08.bits"); -// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181103_134948_9600BPS_CNYICC_Oswego Simulcast_LCN 04.bits"); -// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181103_144312_9600BPS_CNYICC_Oswego Simulcast_LCN 04.bits"); //Interesting UDP port 231 packets (oswego LCN 4) -// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181103_144429_9600BPS_CNYICC_Onondaga Simulcast_LCN 09.bits"); -// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181103_144437_9600BPS_CNYICC_Onondaga Simulcast_LCN 10.bits"); - Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181202_064827_9600BPS_CNYICC_Onondaga Simulcast_LCN 15 Control.bits"); + try(BinaryReader reader = new BinaryReader(path, 200)) + { + while(reader.hasNext()) + { + messageFramer.receive(reader.next()); + } + } + catch(Exception ioe) + { + ioe.printStackTrace(); + } + P25P1MessageProcessor messageProcessor = new P25P1MessageProcessor(); + P25P1CallSequenceRecorder frameRecorder = new P25P1CallSequenceRecorder(new UserPreferences(), 154250000, "", ""); + messageFramer.setListener(messageProcessor); + messageProcessor.setMessageListener(new Listener() + { + @Override + public void receive(IMessage message) + { + frameRecorder.receive(message); + mLog.debug(message.toString()); + } + }); try(BinaryReader reader = new BinaryReader(path, 200)) @@ -510,7 +474,6 @@ else if(patchOnly) ioe.printStackTrace(); } - - mLog.debug("NIDS Detected: " + messageFramer.getDataUnitDetector().getNIDDetectionCount()); + frameRecorder.stop(); } } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25MessageProcessor.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageProcessor.java similarity index 67% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25MessageProcessor.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageProcessor.java index aefb846b0..fb2f680f4 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25MessageProcessor.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageProcessor.java @@ -1,45 +1,51 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25; + */ +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.message.IFrequencyBand; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; import io.github.dsheirer.sample.Listener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.TreeMap; -public class P25MessageProcessor implements Listener +public class P25P1MessageProcessor implements Listener { - private final static Logger mLog = LoggerFactory.getLogger(P25MessageProcessor.class); + private final static Logger mLog = LoggerFactory.getLogger(P25P1MessageProcessor.class); private Listener 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 */ - private Map mFrequencyBandMap = new HashMap(); + private Map mFrequencyBandMap = new TreeMap(); - public P25MessageProcessor() + public P25P1MessageProcessor() { } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/network/P25NetworkConfigurationMonitor.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1NetworkConfigurationMonitor.java similarity index 74% rename from src/main/java/io/github/dsheirer/module/decode/p25/network/P25NetworkConfigurationMonitor.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1NetworkConfigurationMonitor.java index e8052ae81..c6dbd864c 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/network/P25NetworkConfigurationMonitor.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1NetworkConfigurationMonitor.java @@ -1,47 +1,51 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.network; +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.channel.IChannelDescriptor; -import io.github.dsheirer.module.decode.p25.P25Decoder; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCAdjacentSiteStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCAdjacentSiteStatusBroadcastExplicit; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCNetworkStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCNetworkStatusBroadcastExplicit; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCRFSSStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCRFSSStatusBroadcastExplicit; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCSecondaryControlChannelBroadcast; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCSecondaryControlChannelBroadcastExplicit; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCSystemServiceBroadcast; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCAdjacentStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.tsbk.TSBKMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.AdjacentStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.NetworkStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.RFSSStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SNDCPDataChannelAnnouncementExplicit; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SecondaryControlChannelBroadcast; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SystemServiceBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCAdjacentSiteStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCAdjacentSiteStatusBroadcastExplicit; +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.LCRFSSStatusBroadcast; +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.LCSystemServiceBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCAdjacentStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCNetworkStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCRFSSStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.TSBKMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.AdjacentStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.NetworkStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.RFSSStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SNDCPDataChannelAnnouncementExplicit; +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.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,21 +59,23 @@ import java.util.TreeSet; /** - * Tracks the network configuration details of a P25 network from the broadcast messages + * Tracks the network configuration details of a P25 Phase 1 network from the broadcast messages */ -public class P25NetworkConfigurationMonitor +public class P25P1NetworkConfigurationMonitor { - private final static Logger mLog = LoggerFactory.getLogger(P25NetworkConfigurationMonitor.class); + private final static Logger mLog = LoggerFactory.getLogger(P25P1NetworkConfigurationMonitor.class); private Map mFrequencyBandMap = new HashMap<>(); //Network Status Messages + private AMBTCNetworkStatusBroadcast mAMBTCNetworkStatusBroadcast; private NetworkStatusBroadcast mTSBKNetworkStatusBroadcast; private LCNetworkStatusBroadcast mLCNetworkStatusBroadcast; private LCNetworkStatusBroadcastExplicit mLCNetworkStatusBroadcastExplicit; //Current Site Status Messagese private RFSSStatusBroadcast mTSBKRFSSStatusBroadcast; + private AMBTCRFSSStatusBroadcast mAMBTCRFSSStatusBroadcast; private LCRFSSStatusBroadcast mLCRFSSStatusBroadcast; private LCRFSSStatusBroadcastExplicit mLCRFSSStatusBroadcastExplicit; @@ -89,14 +95,14 @@ public class P25NetworkConfigurationMonitor private Map mLCNeighborSitesExplicit = new HashMap<>(); private Map mTSBKNeighborSites = new HashMap<>(); - private P25Decoder.Modulation mModulation; + private P25P1Decoder.Modulation mModulation; /** * Constructs a network configuration monitor. * * @param modulation type used by the decoder */ - public P25NetworkConfigurationMonitor(P25Decoder.Modulation modulation) + public P25P1NetworkConfigurationMonitor(P25P1Decoder.Modulation modulation) { mModulation = modulation; } @@ -146,6 +152,14 @@ public void process(TSBKMessage tsbk) } } break; + case OSP_SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT: + if(tsbk instanceof SecondaryControlChannelBroadcastExplicit) + { + SecondaryControlChannelBroadcastExplicit sccbe = (SecondaryControlChannelBroadcastExplicit)tsbk; + IChannelDescriptor channel = sccbe.getChannel(); + mSecondaryControlChannels.put(channel.toString(), channel); + } + break; case OSP_ADJACENT_STATUS_BROADCAST: if(tsbk instanceof AdjacentStatusBroadcast) { @@ -176,6 +190,18 @@ public void process(AMBTCMessage ambtc) mAMBTCNeighborSites.put((int)aasb.getSite().getValue(), aasb); } break; + case OSP_NETWORK_STATUS_BROADCAST: + if(ambtc instanceof AMBTCNetworkStatusBroadcast) + { + mAMBTCNetworkStatusBroadcast = (AMBTCNetworkStatusBroadcast)ambtc; + } + break; + case OSP_RFSS_STATUS_BROADCAST: + if(ambtc instanceof AMBTCRFSSStatusBroadcast) + { + mAMBTCRFSSStatusBroadcast = (AMBTCRFSSStatusBroadcast)ambtc; + } + break; //TODO: process the rest of the messages here } } @@ -270,14 +296,29 @@ public void process(LinkControlWord lcw) public void reset() { - + mFrequencyBandMap.clear(); + mAMBTCNetworkStatusBroadcast = null; + mTSBKNetworkStatusBroadcast = null; + mLCNetworkStatusBroadcast = null; + mLCNetworkStatusBroadcastExplicit = null; + mTSBKRFSSStatusBroadcast = null; + mLCRFSSStatusBroadcast = null; + mLCRFSSStatusBroadcastExplicit = null; + mSecondaryControlChannels.clear(); + mSNDCPDataChannel = null; + mTSBKSystemServiceBroadcast = null; + mLCSystemServiceBroadcast = null; + mAMBTCNeighborSites = new HashMap<>(); + mLCNeighborSites.clear(); + mLCNeighborSitesExplicit.clear(); + mTSBKNeighborSites.clear(); } public String getActivitySummary() { StringBuilder sb = new StringBuilder(); - sb.append("Activity Summary - Decoder:P25 ").append(mModulation.getLabel()); + sb.append("Activity Summary - Decoder:P25 Phase 1 ").append(mModulation.getLabel()); sb.append("\n\nNetwork\n"); if(mTSBKNetworkStatusBroadcast != null) @@ -287,6 +328,12 @@ public String getActivitySummary() sb.append(" SYSTEM:").append(mTSBKNetworkStatusBroadcast.getSystem()); sb.append(" LRA:").append(mTSBKNetworkStatusBroadcast.getLocationRegistrationArea()); } + else if(mAMBTCNetworkStatusBroadcast != null) + { + sb.append(" NAC:").append(mAMBTCNetworkStatusBroadcast.getNAC()); + sb.append(" WACN:").append(mAMBTCNetworkStatusBroadcast.getWacn()); + sb.append(" SYSTEM:").append(mAMBTCNetworkStatusBroadcast.getSystem()); + } else if(mLCNetworkStatusBroadcast != null) { sb.append(" WACN:").append(mLCNetworkStatusBroadcast.getWACN()); @@ -334,6 +381,18 @@ else if(mLCRFSSStatusBroadcastExplicit != null) sb.append(" DOWNLINK:").append(mLCRFSSStatusBroadcastExplicit.getChannel().getDownlinkFrequency()); sb.append(" UPLINK:").append(mLCRFSSStatusBroadcastExplicit.getChannel().getUplinkFrequency()).append("\n"); } + else if(mAMBTCRFSSStatusBroadcast != null) + { + sb.append(" SYSTEM:").append(mAMBTCRFSSStatusBroadcast.getSystem()); + sb.append(" SITE:").append(mAMBTCRFSSStatusBroadcast.getSite()); + sb.append(" RF SUBSYSTEM:").append(mAMBTCRFSSStatusBroadcast.getRFSS()); + sb.append(" LOCATION REGISTRATION AREA:").append(mAMBTCRFSSStatusBroadcast.getLRA()); + sb.append(" STATUS:").append(mAMBTCRFSSStatusBroadcast.isActiveNetworkConnectionToRfssControllerSite() ? + "ACTIVE RFSS NETWORK CONNECTION\n" : "\n"); + sb.append(" PRI CONTROL CHANNEL:").append(mAMBTCRFSSStatusBroadcast.getChannel()); + sb.append(" DOWNLINK:").append(mAMBTCRFSSStatusBroadcast.getChannel().getDownlinkFrequency()); + sb.append(" UPLINK:").append(mAMBTCRFSSStatusBroadcast.getChannel().getUplinkFrequency()).append("\n"); + } else { sb.append(" UNKNOWN"); diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25SyncDetector.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1SyncDetector.java similarity index 86% rename from src/main/java/io/github/dsheirer/module/decode/p25/P25SyncDetector.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1SyncDetector.java index e4da11e19..fcd2b7e76 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25SyncDetector.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1SyncDetector.java @@ -1,19 +1,23 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25; + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ +package io.github.dsheirer.module.decode.p25.phase1; import io.github.dsheirer.bits.MultiSyncPatternMatcher; import io.github.dsheirer.bits.SoftSyncDetector; @@ -22,10 +26,9 @@ import io.github.dsheirer.dsp.symbol.Dibit; import io.github.dsheirer.dsp.symbol.FrameSync; import io.github.dsheirer.dsp.symbol.ISyncDetectListener; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import io.github.dsheirer.sample.Listener; -public class P25SyncDetector implements Listener +public class P25P1SyncDetector implements Listener { /* Determines the threshold for sync pattern soft matching */ private static final int SYNC_MATCH_THRESHOLD = 4; @@ -45,13 +48,13 @@ public class P25SyncDetector implements Listener private PLLPhaseInversionDetector mInversionDetector90CCW; private PLLPhaseInversionDetector mInversionDetector180; - public P25SyncDetector(ISyncDetectListener syncDetectListener, IPhaseLockedLoop phaseLockedLoop) + public P25P1SyncDetector(ISyncDetectListener syncDetectListener, IPhaseLockedLoop phaseLockedLoop) { //TODO: since we're only going to feed dibits to find next frame, it makes sense to //TODO: update the sync lost parameter to 48 bits .... //TODO: only enable the phase inversion detectors when we're in a sync-lost state - mMatcher = new MultiSyncPatternMatcher(syncDetectListener, DataUnitID.LOGICAL_LINK_DATA_UNIT_1.getMessageLength(), 48); + mMatcher = new MultiSyncPatternMatcher(syncDetectListener, P25P1DataUnitID.LOGICAL_LINK_DATA_UNIT_1.getMessageLength(), 48); mPrimarySyncDetector = new SoftSyncDetector(FrameSync.P25_PHASE1_NORMAL.getSync(), SYNC_MATCH_THRESHOLD, syncDetectListener); mMatcher.add(mPrimarySyncDetector); diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/IAdjacentSite.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/IAdjacentSite.java new file mode 100644 index 000000000..fa23f2204 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/IAdjacentSite.java @@ -0,0 +1,44 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message; + +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; + +/** + * Interface for adjacent site (ie neighbor) messages + */ +public interface IAdjacentSite +{ + String getUniqueID(); + + Identifier getRFSSId(); + + Identifier getSystemID(); + + Identifier getSiteID(); + + Identifier getLRAId(); + + String getSystemServiceClass(); + + IChannelDescriptor getChannel(); +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/IFrequencyBand.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/IFrequencyBand.java similarity index 63% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/IFrequencyBand.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/IFrequencyBand.java index 6ebd3fbe4..387fbf1fc 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/IFrequencyBand.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/IFrequencyBand.java @@ -1,19 +1,23 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25.message; + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ +package io.github.dsheirer.module.decode.p25.phase1.message; public interface IFrequencyBand { diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/IFrequencyBandReceiver.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/IFrequencyBandReceiver.java similarity index 52% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/IFrequencyBandReceiver.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/IFrequencyBandReceiver.java index 1c5c24418..ed2effd7a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/IFrequencyBandReceiver.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/IFrequencyBandReceiver.java @@ -1,19 +1,23 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25.message; + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ +package io.github.dsheirer.module.decode.p25.phase1.message; import io.github.dsheirer.channel.IChannelDescriptor; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/P25Message.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/P25Message.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/P25Message.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/P25Message.java index ff50b0339..6cbde82c0 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/P25Message.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/P25Message.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -17,13 +17,13 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message; +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.module.decode.p25.identifier.APCO25Nac; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; import io.github.dsheirer.protocol.Protocol; public abstract class P25Message extends Message @@ -102,7 +102,7 @@ public Identifier getNAC() /** * Data Unit ID indicates the type of P25 message */ - public abstract DataUnitID getDUID(); + public abstract P25P1DataUnitID getDUID(); public String toString() { diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/P25MessageFactory.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/P25MessageFactory.java similarity index 61% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/P25MessageFactory.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/P25MessageFactory.java index cb213945b..ccce5d776 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/P25MessageFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/P25MessageFactory.java @@ -1,29 +1,33 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25.message; + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ +package io.github.dsheirer.module.decode.p25.phase1.message; import io.github.dsheirer.bits.CorrectedBinaryMessage; -import io.github.dsheirer.module.decode.p25.message.hdu.HDUMessage; -import io.github.dsheirer.module.decode.p25.message.ldu.LDU1Message; -import io.github.dsheirer.module.decode.p25.message.ldu.LDU2Message; -import io.github.dsheirer.module.decode.p25.message.tdu.TDULinkControlMessage; -import io.github.dsheirer.module.decode.p25.message.tdu.TDUMessage; -import io.github.dsheirer.module.decode.p25.message.vselp.VSELP1Message; -import io.github.dsheirer.module.decode.p25.message.vselp.VSELP2Message; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.hdu.HDUMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU1Message; +import io.github.dsheirer.module.decode.p25.phase1.message.ldu.LDU2Message; +import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDULinkControlMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tdu.TDUMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.vselp.VSELP1Message; +import io.github.dsheirer.module.decode.p25.phase1.message.vselp.VSELP2Message; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,7 +50,7 @@ public class P25MessageFactory * correction * @return constructed message parser */ - public static P25Message create(DataUnitID dataUnitID, int nac, long timestamp, CorrectedBinaryMessage message) + public static P25Message create(P25P1DataUnitID dataUnitID, int nac, long timestamp, CorrectedBinaryMessage message) { switch(dataUnitID) { diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/UnknownP25Message.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/UnknownP25Message.java similarity index 84% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/UnknownP25Message.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/UnknownP25Message.java index 3b6ac01de..f58f1051b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/UnknownP25Message.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/UnknownP25Message.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,11 +18,11 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message; +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.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; import java.util.Collections; import java.util.List; @@ -32,16 +32,16 @@ */ public class UnknownP25Message extends P25Message { - private DataUnitID mDataUnitID; + private P25P1DataUnitID mDataUnitID; - public UnknownP25Message(CorrectedBinaryMessage message, int nac, long timestamp, DataUnitID dataUnitID) + public UnknownP25Message(CorrectedBinaryMessage message, int nac, long timestamp, P25P1DataUnitID dataUnitID) { super(message, nac); mDataUnitID = dataUnitID; } @Override - public DataUnitID getDUID() + public P25P1DataUnitID getDUID() { return mDataUnitID; } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/AMBTCMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/AMBTCMessageFilter.java similarity index 88% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/filter/AMBTCMessageFilter.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/AMBTCMessageFilter.java index 233f34e56..fe065b3cb 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/AMBTCMessageFilter.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/AMBTCMessageFilter.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.filter; +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.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.Collections; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/HDUMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/HDUMessageFilter.java new file mode 100644 index 000000000..ccc837014 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/HDUMessageFilter.java @@ -0,0 +1,55 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +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.hdu.HDUMessage; + +import java.util.Collections; +import java.util.List; + +public class HDUMessageFilter extends Filter +{ + public HDUMessageFilter() + { + super("Header Data Unit"); + } + + @Override + public boolean passes(IMessage message) + { + return mEnabled && canProcess(message); + } + + @Override + public boolean canProcess(IMessage message) + { + return message instanceof HDUMessage; + } + + @Override + public List> getFilterElements() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/IPPacketMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/IPPacketMessageFilter.java similarity index 88% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/filter/IPPacketMessageFilter.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/IPPacketMessageFilter.java index 17bf3ef19..f22d0c858 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/IPPacketMessageFilter.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/IPPacketMessageFilter.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.filter; +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.message.pdu.packet.PacketMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.PacketMessage; import java.util.Collections; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/LDUMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/LDUMessageFilter.java new file mode 100644 index 000000000..6f7fb6cd5 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/LDUMessageFilter.java @@ -0,0 +1,55 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +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.ldu.LDUMessage; + +import java.util.Collections; +import java.util.List; + +public class LDUMessageFilter extends Filter +{ + public LDUMessageFilter() + { + super("Link Data Unit"); + } + + @Override + public boolean passes(IMessage message) + { + return mEnabled && canProcess(message); + } + + @Override + public boolean canProcess(IMessage message) + { + return message instanceof LDUMessage; + } + + @Override + public List> getFilterElements() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/P25MessageFilterSet.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/P25MessageFilterSet.java new file mode 100644 index 000000000..28dd12c2a --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/P25MessageFilterSet.java @@ -0,0 +1,52 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.filter; + +import io.github.dsheirer.filter.FilterSet; +import io.github.dsheirer.message.IMessage; +import io.github.dsheirer.message.SyncLossMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.P25Message; + +public class P25MessageFilterSet extends FilterSet +{ + public P25MessageFilterSet() + { + super("P25 Message Filter"); + + addFilter(new AMBTCMessageFilter()); + addFilter(new HDUMessageFilter()); + addFilter(new IPPacketMessageFilter()); + addFilter(new LDUMessageFilter()); + addFilter(new PDUMessageFilter()); + addFilter(new SNDCPMessageFilter()); + addFilter(new SyncLossMessageFilter()); + addFilter(new TDUMessageFilter()); + addFilter(new TDULCMessageFilter()); + addFilter(new TSBKMessageFilterSet()); + addFilter(new UMBTCMessageFilter()); + } + + @Override + public boolean canProcess(IMessage message) + { + return message instanceof P25Message || message instanceof SyncLossMessage; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/PDUMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/PDUMessageFilter.java similarity index 53% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/filter/PDUMessageFilter.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/PDUMessageFilter.java index 7ea842c04..67bb287c5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/PDUMessageFilter.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/PDUMessageFilter.java @@ -1,10 +1,30 @@ -package io.github.dsheirer.module.decode.p25.message.filter; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +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.message.pdu.PDUMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/SNDCPMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/SNDCPMessageFilter.java similarity index 88% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/filter/SNDCPMessageFilter.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/SNDCPMessageFilter.java index 54e7e621a..00bb34691 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/SNDCPMessageFilter.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/SNDCPMessageFilter.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.filter; +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.message.pdu.packet.sndcp.SNDCPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPMessage; import java.util.Collections; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/SyncLossMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/SyncLossMessageFilter.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/filter/SyncLossMessageFilter.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/SyncLossMessageFilter.java index d32c0aacb..be973b5ca 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/SyncLossMessageFilter.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/SyncLossMessageFilter.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.filter; +package io.github.dsheirer.module.decode.p25.phase1.message.filter; import io.github.dsheirer.filter.Filter; import io.github.dsheirer.filter.FilterElement; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/TDULCMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/TDULCMessageFilter.java new file mode 100644 index 000000000..c1c6b04f5 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/TDULCMessageFilter.java @@ -0,0 +1,55 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +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.tdu.TDULinkControlMessage; + +import java.util.Collections; +import java.util.List; + +public class TDULCMessageFilter extends Filter +{ + public TDULCMessageFilter() + { + super("TDU Terminator Data Unit with Link Control"); + } + + @Override + public boolean passes(IMessage message) + { + return mEnabled && canProcess(message); + } + + @Override + public boolean canProcess(IMessage message) + { + return message instanceof TDULinkControlMessage; + } + + @Override + public List> getFilterElements() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/TDUMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/TDUMessageFilter.java new file mode 100644 index 000000000..f47bf304e --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/TDUMessageFilter.java @@ -0,0 +1,55 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +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.tdu.TDUMessage; + +import java.util.Collections; +import java.util.List; + +public class TDUMessageFilter extends Filter +{ + public TDUMessageFilter() + { + super("TDU Terminator Data Unit"); + } + + @Override + public boolean passes(IMessage message) + { + return mEnabled && canProcess(message); + } + + @Override + public boolean canProcess(IMessage message) + { + return message instanceof TDUMessage; + } + + @Override + public List> getFilterElements() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/TSBKMessageFilterSet.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/TSBKMessageFilterSet.java similarity index 68% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/filter/TSBKMessageFilterSet.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/TSBKMessageFilterSet.java index e96abe9e4..132a4014e 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/TSBKMessageFilterSet.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/TSBKMessageFilterSet.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.filter; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +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.filter.FilterSet; import io.github.dsheirer.message.IMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; -import io.github.dsheirer.module.decode.p25.message.tsbk.TSBKMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.TSBKMessage; import io.github.dsheirer.module.decode.p25.reference.Vendor; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/UMBTCMessageFilter.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/UMBTCMessageFilter.java similarity index 88% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/filter/UMBTCMessageFilter.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/UMBTCMessageFilter.java index a8c923eaa..e355a9cea 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/filter/UMBTCMessageFilter.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/filter/UMBTCMessageFilter.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.filter; +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.message.pdu.umbtc.UMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.umbtc.UMBTCMessage; import java.util.Collections; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/hdu/HDUMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/hdu/HDUMessage.java similarity index 86% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/hdu/HDUMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/hdu/HDUMessage.java index 016fa344d..8043950bb 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/hdu/HDUMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/hdu/HDUMessage.java @@ -1,27 +1,33 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25.message.hdu; + */ +package io.github.dsheirer.module.decode.p25.phase1.message.hdu; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.edac.Golay18; import io.github.dsheirer.edac.ReedSolomon_63_47_17; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.P25Message; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -79,9 +85,9 @@ public HDUMessage(CorrectedBinaryMessage message, int nac, long timestamp) } @Override - public DataUnitID getDUID() + public P25P1DataUnitID getDUID() { - return DataUnitID.HEADER_DATA_UNIT; + return P25P1DataUnitID.HEADER_DATA_UNIT; } public HeaderData getHeaderData() @@ -188,7 +194,7 @@ private void extractHeaderData() else { //If we corrected any bit errors, update the original message with the bit error count - for(int x = 0; x < 23; x++) + for(int x = 0; x <= 35; x++) { if(output[x] != input[x]) { diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/hdu/HeaderData.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/hdu/HeaderData.java similarity index 77% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/hdu/HeaderData.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/hdu/HeaderData.java index a3e7c3993..f34804ef5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/hdu/HeaderData.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/hdu/HeaderData.java @@ -1,27 +1,30 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.hdu; +package io.github.dsheirer.module.decode.p25.phase1.message.hdu; import io.github.dsheirer.bits.BinaryMessage; 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.talkgroup.APCO25ToTalkgroup; import io.github.dsheirer.module.decode.p25.reference.Encryption; @@ -130,8 +133,8 @@ public Identifier getEncryptionKey() { if(mEncryptionKey == null && isEncryptedAudio()) { - mEncryptionKey = APCO25EncryptionKey.create(getMessage().getInt(ALGORITHM_ID), - getMessage().getInt(KEY_ID)); + mEncryptionKey = EncryptionKeyIdentifier.create(APCO25EncryptionKey.create(getMessage().getInt(ALGORITHM_ID), + getMessage().getInt(KEY_ID))); } return mEncryptionKey; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/LinkControlOpcode.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/LinkControlOpcode.java similarity index 98% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/LinkControlOpcode.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/LinkControlOpcode.java index a7c6e1a8e..6a8fddddf 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/LinkControlOpcode.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/LinkControlOpcode.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc; +package io.github.dsheirer.module.decode.p25.phase1.message.lc; import io.github.dsheirer.module.decode.p25.reference.Vendor; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/LinkControlWord.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/LinkControlWord.java similarity index 97% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/LinkControlWord.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/LinkControlWord.java index 56bfc2926..3da7c17d1 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/LinkControlWord.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/LinkControlWord.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc; +package io.github.dsheirer.module.decode.p25.phase1.message.lc; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/LinkControlWordFactory.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/LinkControlWordFactory.java similarity index 60% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/LinkControlWordFactory.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/LinkControlWordFactory.java index 0773ee1de..eb5719284 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/LinkControlWordFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/LinkControlWordFactory.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,43 +18,43 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc; +package io.github.dsheirer.module.decode.p25.phase1.message.lc; import io.github.dsheirer.bits.BinaryMessage; -import io.github.dsheirer.module.decode.p25.message.lc.motorola.LCMotorolaPatchGroupAdd; -import io.github.dsheirer.module.decode.p25.message.lc.motorola.LCMotorolaPatchGroupDelete; -import io.github.dsheirer.module.decode.p25.message.lc.motorola.LCMotorolaPatchGroupVoiceChannelUpdate; -import io.github.dsheirer.module.decode.p25.message.lc.motorola.LCMotorolaPatchGroupVoiceChannelUser; -import io.github.dsheirer.module.decode.p25.message.lc.motorola.LCMotorolaTalkComplete; -import io.github.dsheirer.module.decode.p25.message.lc.motorola.LCMotorolaUnknownOpcode; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCAdjacentSiteStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCAdjacentSiteStatusBroadcastExplicit; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCCallAlert; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCCallTermination; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCExtendedFunctionCommand; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCFrequencyBandUpdate; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCFrequencyBandUpdateExplicit; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCGroupAffiliationQuery; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCGroupVoiceChannelUpdate; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCGroupVoiceChannelUpdateExplicit; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCGroupVoiceChannelUser; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCMessageUpdate; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCNetworkStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCNetworkStatusBroadcastExplicit; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCProtectionParameterBroadcast; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCRFSSStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCRFSSStatusBroadcastExplicit; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCSecondaryControlChannelBroadcast; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCSecondaryControlChannelBroadcastExplicit; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCStatusQuery; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCStatusUpdate; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCSystemServiceBroadcast; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCTelephoneInterconnectAnswerRequest; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCTelephoneInterconnectVoiceChannelUser; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCUnitAuthenticationCommand; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCUnitRegistrationCommand; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCUnitToUnitAnswerRequest; -import io.github.dsheirer.module.decode.p25.message.lc.standard.LCUnitToUnitVoiceChannelUser; +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.LCMotorolaTalkComplete; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola.LCMotorolaUnknownOpcode; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCAdjacentSiteStatusBroadcast; +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.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.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.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; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCRFSSStatusBroadcast; +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.LCStatusQuery; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCStatusUpdate; +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; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.standard.LCUnitAuthenticationCommand; +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; /** * Factory class for creating link control word (LCW) message parsers. diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/UnknownLinkControlWord.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/UnknownLinkControlWord.java new file mode 100644 index 000000000..9d5547ba9 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/UnknownLinkControlWord.java @@ -0,0 +1,59 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.lc; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.identifier.Identifier; + +import java.util.Collections; +import java.util.List; + +/** + * Unknown link control word. + */ +public class UnknownLinkControlWord extends LinkControlWord +{ + /** + * Constructs a Link Control Word from the binary message sequence. + * + * @param message + */ + public UnknownLinkControlWord(BinaryMessage message) + { + super(message); + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getMessageStub()); + sb.append(" UNKNOWN/UNRECOGNIZED OPCODE"); + sb.append(" MSG:").append(getMessage().toHexString()); + return sb.toString(); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaPatchGroupAdd.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaPatchGroupAdd.java similarity index 97% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaPatchGroupAdd.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaPatchGroupAdd.java index 13c36c123..8dfcd755b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaPatchGroupAdd.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaPatchGroupAdd.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.motorola; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaPatchGroupDelete.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaPatchGroupDelete.java similarity index 97% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaPatchGroupDelete.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaPatchGroupDelete.java index c4d1ca492..ff6010c2c 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaPatchGroupDelete.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaPatchGroupDelete.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.motorola; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaPatchGroupVoiceChannelUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaPatchGroupVoiceChannelUpdate.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaPatchGroupVoiceChannelUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaPatchGroupVoiceChannelUpdate.java index 4ca11908f..156b9d83d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaPatchGroupVoiceChannelUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaPatchGroupVoiceChannelUpdate.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.motorola; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -27,7 +27,7 @@ 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.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaPatchGroupVoiceChannelUser.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaPatchGroupVoiceChannelUser.java similarity index 97% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaPatchGroupVoiceChannelUser.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaPatchGroupVoiceChannelUser.java index 6773aa271..b1a0ecf47 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaPatchGroupVoiceChannelUser.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaPatchGroupVoiceChannelUser.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.motorola; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaTalkComplete.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaTalkComplete.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaTalkComplete.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaTalkComplete.java index d67f9fc9b..816f08d69 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaTalkComplete.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaTalkComplete.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.motorola; +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.module.decode.p25.identifier.talkgroup.APCO25AnyTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaUnknownOpcode.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaUnknownOpcode.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaUnknownOpcode.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaUnknownOpcode.java index 8e4e6f506..aa6a5d6f9 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/LCMotorolaUnknownOpcode.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/LCMotorolaUnknownOpcode.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.motorola; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/MotorolaLinkControlWord.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/MotorolaLinkControlWord.java similarity index 85% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/MotorolaLinkControlWord.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/MotorolaLinkControlWord.java index 0ad4ffaa9..60ec376d1 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/motorola/MotorolaLinkControlWord.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/motorola/MotorolaLinkControlWord.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,10 +18,10 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.motorola; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.motorola; import io.github.dsheirer.bits.BinaryMessage; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; public abstract class MotorolaLinkControlWord extends LinkControlWord { diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCAdjacentSiteStatusBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCAdjacentSiteStatusBroadcast.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCAdjacentSiteStatusBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCAdjacentSiteStatusBroadcast.java index efdd966fa..eaa92b16e 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCAdjacentSiteStatusBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCAdjacentSiteStatusBroadcast.java @@ -1,24 +1,26 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -28,9 +30,9 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; import io.github.dsheirer.module.decode.p25.identifier.APCO25System; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; -import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; +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; @@ -54,7 +56,7 @@ public class LCAdjacentSiteStatusBroadcast extends LinkControlWord implements IF private Identifier mRFSS; private Identifier mSite; private IChannelDescriptor mChannel; - private VoiceServiceOptions mVoiceServiceOptions; + private SystemServiceClass mSystemServiceClass; /** * Constructs a Link Control Word from the binary message sequence. @@ -75,7 +77,7 @@ public String toString() sb.append(" SYSTEM:").append(getSystem()); sb.append(" LRA:").append(getLocationRegistrationArea()); sb.append(" CHAN:" + getChannel()); - sb.append(" SERVICE OPTIONS:").append(getVoiceServiceOptions()); + sb.append(" SERVICE OPTIONS:").append(getSystemServiceClass()); return sb.toString(); } @@ -124,20 +126,20 @@ public IChannelDescriptor getChannel() if(mChannel == null) { mChannel = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND), - getMessage().getInt(CHANNEL_NUMBER)); + getMessage().getInt(CHANNEL_NUMBER)); } return mChannel; } - public VoiceServiceOptions getVoiceServiceOptions() + public SystemServiceClass getSystemServiceClass() { - if(mVoiceServiceOptions == null) + if(mSystemServiceClass == null) { - mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_CLASS)); + mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS)); } - return mVoiceServiceOptions; + return mSystemServiceClass; } /** diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCAdjacentSiteStatusBroadcastExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCAdjacentSiteStatusBroadcastExplicit.java similarity index 70% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCAdjacentSiteStatusBroadcastExplicit.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCAdjacentSiteStatusBroadcastExplicit.java index 093414f43..86623c11d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCAdjacentSiteStatusBroadcastExplicit.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCAdjacentSiteStatusBroadcastExplicit.java @@ -1,24 +1,26 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -27,9 +29,9 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; -import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; +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; @@ -53,7 +55,7 @@ public class LCAdjacentSiteStatusBroadcastExplicit extends LinkControlWord imple private Identifier mRFSS; private Identifier mSite; private IChannelDescriptor mChannel; - private VoiceServiceOptions mVoiceServiceOptions; + private SystemServiceClass mSystemServiceClass; /** * Constructs a Link Control Word from the binary message sequence. @@ -73,7 +75,7 @@ public String toString() sb.append(" SITE:" + getSite()); sb.append(" LRA:").append(getLocationRegistrationArea()); sb.append(" CHAN:" + getChannel()); - sb.append(" SERVICE OPTIONS:").append(getVoiceServiceOptions()); + sb.append(" SERVICE OPTIONS:").append(getSystemServiceClass()); return sb.toString(); } @@ -119,14 +121,14 @@ public IChannelDescriptor getChannel() return mChannel; } - public VoiceServiceOptions getVoiceServiceOptions() + public SystemServiceClass getSystemServiceClass() { - if(mVoiceServiceOptions == null) + if(mSystemServiceClass == null) { - mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_CLASS)); + mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS)); } - return mVoiceServiceOptions; + return mSystemServiceClass; } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCCallAlert.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCCallAlert.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCCallAlert.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCCallAlert.java index 180ca27e4..f239b0136 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCCallAlert.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCCallAlert.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,13 +18,13 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCCallTermination.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCCallTermination.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCCallTermination.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCCallTermination.java index 8e59840eb..f552d720d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCCallTermination.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCCallTermination.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25AnyTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCExtendedFunctionCommand.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCExtendedFunctionCommand.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCExtendedFunctionCommand.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCExtendedFunctionCommand.java index 223e0e846..32c94f829 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCExtendedFunctionCommand.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCExtendedFunctionCommand.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import io.github.dsheirer.module.decode.p25.reference.ExtendedFunction; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCFrequencyBandUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCFrequencyBandUpdate.java similarity index 72% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCFrequencyBandUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCFrequencyBandUpdate.java index 16bd64337..893b83d58 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCFrequencyBandUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCFrequencyBandUpdate.java @@ -1,29 +1,31 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +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; @@ -90,7 +92,7 @@ public int getBandwidth() @Override public long getTransmitOffset() { - long offset = getMessage().getLong(TRANSMIT_OFFSET) * 250000l; + long offset = getMessage().getLong(TRANSMIT_OFFSET) * getChannelSpacing(); if(!getMessage().get(TRANSMIT_OFFSET_SIGN)) { diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCFrequencyBandUpdateExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCFrequencyBandUpdateExplicit.java similarity index 73% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCFrequencyBandUpdateExplicit.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCFrequencyBandUpdateExplicit.java index 7bb8a994c..ae97a572a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCFrequencyBandUpdateExplicit.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCFrequencyBandUpdateExplicit.java @@ -1,29 +1,31 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +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; @@ -101,7 +103,7 @@ else if(bandwidth == 0x5) @Override public long getTransmitOffset() { - long offset = getMessage().getLong(TRANSMIT_OFFSET) * 250000l; + long offset = getMessage().getLong(TRANSMIT_OFFSET) * getChannelSpacing(); if(!getMessage().get(TRANSMIT_OFFSET_SIGN)) { diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCGroupAffiliationQuery.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCGroupAffiliationQuery.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCGroupAffiliationQuery.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCGroupAffiliationQuery.java index 458020fc6..368435caf 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCGroupAffiliationQuery.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCGroupAffiliationQuery.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,13 +18,13 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCGroupVoiceChannelUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCGroupVoiceChannelUpdate.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCGroupVoiceChannelUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCGroupVoiceChannelUpdate.java index bae78da1d..2377c46cd 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCGroupVoiceChannelUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCGroupVoiceChannelUpdate.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; 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.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +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; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCGroupVoiceChannelUpdateExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCGroupVoiceChannelUpdateExplicit.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCGroupVoiceChannelUpdateExplicit.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCGroupVoiceChannelUpdateExplicit.java index e3d394194..1f78eac10 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCGroupVoiceChannelUpdateExplicit.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCGroupVoiceChannelUpdateExplicit.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +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 java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCGroupVoiceChannelUser.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCGroupVoiceChannelUser.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCGroupVoiceChannelUser.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCGroupVoiceChannelUser.java index f9dc42dc1..750f8e958 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCGroupVoiceChannelUser.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCGroupVoiceChannelUser.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,13 +18,13 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCMessageUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCMessageUpdate.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCMessageUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCMessageUpdate.java index 158ef5edb..acae8ea53 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCMessageUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCMessageUpdate.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.message.APCO25ShortDataMessage; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCNetworkStatusBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCNetworkStatusBroadcast.java similarity index 65% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCNetworkStatusBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCNetworkStatusBroadcast.java index f17caeb62..03415a409 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCNetworkStatusBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCNetworkStatusBroadcast.java @@ -1,24 +1,26 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -26,9 +28,9 @@ 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.channel.APCO25Channel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; -import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; +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; @@ -49,7 +51,7 @@ public class LCNetworkStatusBroadcast extends LinkControlWord implements IFreque private Identifier mWACN; private Identifier mSystem; private IChannelDescriptor mChannel; - private VoiceServiceOptions mVoiceServiceOptions; + private SystemServiceClass mSystemServiceClass; /** * Constructs a Link Control Word from the binary message sequence. @@ -68,7 +70,7 @@ public String toString() sb.append(" WACN:").append(getWACN()); sb.append(" SYSTEM:").append(getSystem()); sb.append(" CHAN:" + getChannel()); - sb.append(" SERVICE OPTIONS:" + getVoiceServiceOptions()); + sb.append(" SERVICE OPTIONS:" + getSystemServiceClass()); return sb.toString(); } @@ -103,14 +105,14 @@ public IChannelDescriptor getChannel() return mChannel; } - public VoiceServiceOptions getVoiceServiceOptions() + public SystemServiceClass getSystemServiceClass() { - if(mVoiceServiceOptions == null) + if(mSystemServiceClass == null) { - mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_CLASS)); + mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS)); } - return mVoiceServiceOptions; + return mSystemServiceClass; } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCNetworkStatusBroadcastExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCNetworkStatusBroadcastExplicit.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCNetworkStatusBroadcastExplicit.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCNetworkStatusBroadcastExplicit.java index 39d70e4bd..6bdd2246a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCNetworkStatusBroadcastExplicit.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCNetworkStatusBroadcastExplicit.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -26,8 +26,8 @@ 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.channel.APCO25ExplicitChannel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +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; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCProtectionParameterBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCProtectionParameterBroadcast.java similarity index 64% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCProtectionParameterBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCProtectionParameterBroadcast.java index a2c2bf2e2..eba951bf4 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCProtectionParameterBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCProtectionParameterBroadcast.java @@ -1,30 +1,33 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; 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.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import java.util.ArrayList; import java.util.List; @@ -67,7 +70,8 @@ public Identifier getEncryptionKey() { if(mEncryptionKey == null) { - mEncryptionKey = APCO25EncryptionKey.create(getMessage().getInt(ALGORITHM_ID), getMessage().getInt(KEY_ID)); + mEncryptionKey = EncryptionKeyIdentifier.create(APCO25EncryptionKey.create(getMessage().getInt(ALGORITHM_ID), + getMessage().getInt(KEY_ID))); } return mEncryptionKey; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCRFSSStatusBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCRFSSStatusBroadcast.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCRFSSStatusBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCRFSSStatusBroadcast.java index 0277aa8dd..8c58c9b38 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCRFSSStatusBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCRFSSStatusBroadcast.java @@ -1,24 +1,26 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -28,9 +30,9 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; import io.github.dsheirer.module.decode.p25.identifier.APCO25System; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; -import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; +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; @@ -54,7 +56,7 @@ public class LCRFSSStatusBroadcast extends LinkControlWord implements IFrequency private Identifier mRFSS; private Identifier mSite; private IChannelDescriptor mChannel; - private VoiceServiceOptions mVoiceServiceOptions; + private SystemServiceClass mSystemServiceClass; /** * Constructs a Link Control Word from the binary message sequence. @@ -74,7 +76,7 @@ public String toString() sb.append(" SYSTEM:").append(getSystem()); sb.append(" SITE:" + getRfss() + "-" + getSite()); sb.append(" CHAN:" + getChannel()); - sb.append(" SERVICE OPTIONS:" + getVoiceServiceOptions()); + sb.append(" SERVICE OPTIONS:" + getSystemServiceClass()); return sb.toString(); } @@ -123,20 +125,20 @@ public IChannelDescriptor getChannel() if(mChannel == null) { mChannel = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND), - getMessage().getInt(CHANNEL_NUMBER)); + getMessage().getInt(CHANNEL_NUMBER)); } return mChannel; } - public VoiceServiceOptions getVoiceServiceOptions() + public SystemServiceClass getSystemServiceClass() { - if(mVoiceServiceOptions == null) + if(mSystemServiceClass == null) { - mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_CLASS)); + mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS)); } - return mVoiceServiceOptions; + return mSystemServiceClass; } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCRFSSStatusBroadcastExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCRFSSStatusBroadcastExplicit.java similarity index 70% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCRFSSStatusBroadcastExplicit.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCRFSSStatusBroadcastExplicit.java index c113ff1b3..00a26a3cb 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCRFSSStatusBroadcastExplicit.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCRFSSStatusBroadcastExplicit.java @@ -1,24 +1,26 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -27,9 +29,9 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; -import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; +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; @@ -53,7 +55,7 @@ public class LCRFSSStatusBroadcastExplicit extends LinkControlWord implements IF private Identifier mRFSS; private Identifier mSite; private IChannelDescriptor mChannel; - private VoiceServiceOptions mVoiceServiceOptions; + private SystemServiceClass mSystemServiceClass; /** * Constructs a Link Control Word from the binary message sequence. @@ -72,7 +74,7 @@ public String toString() sb.append(" LRA:").append(getLocationRegistrationArea()); sb.append(" SITE:" + getRfss() + "-" + getSite()); sb.append(" CHAN:" + getChannel()); - sb.append(" SERVICE OPTIONS:" + getVoiceServiceOptions()); + sb.append(" SERVICE OPTIONS:" + getSystemServiceClass()); return sb.toString(); } @@ -118,14 +120,14 @@ public IChannelDescriptor getChannel() return mChannel; } - public VoiceServiceOptions getVoiceServiceOptions() + public SystemServiceClass getSystemServiceClass() { - if(mVoiceServiceOptions == null) + if(mSystemServiceClass == null) { - mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_CLASS)); + mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS)); } - return mVoiceServiceOptions; + return mSystemServiceClass; } /** diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCSecondaryControlChannelBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCSecondaryControlChannelBroadcast.java similarity index 66% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCSecondaryControlChannelBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCSecondaryControlChannelBroadcast.java index 41a76c734..24a720107 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCSecondaryControlChannelBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCSecondaryControlChannelBroadcast.java @@ -1,24 +1,26 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -26,9 +28,9 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; -import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; +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; @@ -52,8 +54,8 @@ public class LCSecondaryControlChannelBroadcast extends LinkControlWord implemen private Identifier mSite; private IChannelDescriptor mChannelA; private IChannelDescriptor mChannelB; - private VoiceServiceOptions mVoiceServiceOptionsA; - private VoiceServiceOptions mVoiceServiceOptionsB; + private SystemServiceClass mSystemServiceClassA; + private SystemServiceClass mSystemServiceClassB; /** * Constructs a Link Control Word from the binary message sequence. @@ -71,12 +73,12 @@ public String toString() sb.append(getMessageStub()); sb.append(" SITE:" + getRFSS() + "-" + getSite()); sb.append(" CHAN A:" + getChannelA()); - sb.append(" SERVICE OPTIONS:" + getVoiceServiceOptionsA()); + sb.append(" SERVICE CLASS:" + getSystemServiceClassA()); if(hasChannelB()) { sb.append(" CHAN B:" + getChannelB()); - sb.append(" SERVICE OPTIONS:" + getVoiceServiceOptionsB()); + sb.append(" SERVICE CLASS:" + getSystemServiceClassB()); } return sb.toString(); } @@ -129,25 +131,25 @@ public IChannelDescriptor getChannelB() return mChannelB; } - public VoiceServiceOptions getVoiceServiceOptionsA() + public SystemServiceClass getSystemServiceClassA() { - if(mVoiceServiceOptionsA == null) + if(mSystemServiceClassA == null) { - mVoiceServiceOptionsA = new VoiceServiceOptions(getMessage().getInt(SERVICE_CLASS_A)); + mSystemServiceClassA = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS_A)); } - return mVoiceServiceOptionsA; + return mSystemServiceClassA; } - public VoiceServiceOptions getVoiceServiceOptionsB() + public SystemServiceClass getSystemServiceClassB() { - if(mVoiceServiceOptionsB == null) + if(mSystemServiceClassB == null) { - mVoiceServiceOptionsB = new VoiceServiceOptions(getMessage().getInt(SERVICE_CLASS_B)); + mSystemServiceClassB = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS_B)); } - return mVoiceServiceOptionsB; + return mSystemServiceClassB; } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCSecondaryControlChannelBroadcastExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCSecondaryControlChannelBroadcastExplicit.java similarity index 67% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCSecondaryControlChannelBroadcastExplicit.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCSecondaryControlChannelBroadcastExplicit.java index 08dae298a..9bfe29f83 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCSecondaryControlChannelBroadcastExplicit.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCSecondaryControlChannelBroadcastExplicit.java @@ -1,24 +1,26 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -26,9 +28,9 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; -import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; +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; @@ -51,7 +53,7 @@ public class LCSecondaryControlChannelBroadcastExplicit extends LinkControlWord private Identifier mRFSS; private Identifier mSite; private IChannelDescriptor mChannel; - private VoiceServiceOptions mVoiceServiceOptions; + private SystemServiceClass mSystemServiceClass; /** * Constructs a Link Control Word from the binary message sequence. @@ -69,7 +71,7 @@ public String toString() sb.append(getMessageStub()); sb.append(" SITE:" + getRFSS() + "-" + getSite()); sb.append(" CHAN:" + getChannel()); - sb.append(" SERVICE OPTIONS:").append(getVoiceServiceOptions()); + sb.append(" SERVICE CLASS:").append(getSystemServiceClass()); return sb.toString(); } @@ -105,14 +107,14 @@ public IChannelDescriptor getChannel() return mChannel; } - public VoiceServiceOptions getVoiceServiceOptions() + public SystemServiceClass getSystemServiceClass() { - if(mVoiceServiceOptions == null) + if(mSystemServiceClass == null) { - mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_CLASS)); + mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SERVICE_CLASS)); } - return mVoiceServiceOptions; + return mSystemServiceClass; } /** diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCStatusQuery.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCStatusQuery.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCStatusQuery.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCStatusQuery.java index 32042879b..3847e6d24 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCStatusQuery.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCStatusQuery.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,13 +18,13 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCStatusUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCStatusUpdate.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCStatusUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCStatusUpdate.java index f09e36881..df282e064 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCStatusUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCStatusUpdate.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; @@ -26,7 +26,7 @@ import io.github.dsheirer.module.decode.p25.identifier.status.APCO25UserStatus; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCSystemServiceBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCSystemServiceBroadcast.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCSystemServiceBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCSystemServiceBroadcast.java index 0db52d790..f095cfaed 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCSystemServiceBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCSystemServiceBroadcast.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,11 +18,11 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import io.github.dsheirer.module.decode.p25.reference.Service; import java.util.Collections; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCTelephoneInterconnectAnswerRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCTelephoneInterconnectAnswerRequest.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCTelephoneInterconnectAnswerRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCTelephoneInterconnectAnswerRequest.java index 48dd63da5..7fe8652c7 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCTelephoneInterconnectAnswerRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCTelephoneInterconnectAnswerRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,13 +18,13 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.telephone.APCO25TelephoneNumber; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import io.github.dsheirer.module.decode.p25.reference.Digit; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCTelephoneInterconnectVoiceChannelUser.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCTelephoneInterconnectVoiceChannelUser.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCTelephoneInterconnectVoiceChannelUser.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCTelephoneInterconnectVoiceChannelUser.java index ccda878a0..7505caaed 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCTelephoneInterconnectVoiceChannelUser.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCTelephoneInterconnectVoiceChannelUser.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25AnyTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCUnitAuthenticationCommand.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCUnitAuthenticationCommand.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCUnitAuthenticationCommand.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCUnitAuthenticationCommand.java index 51bc2790c..ee29c5c73 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCUnitAuthenticationCommand.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCUnitAuthenticationCommand.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; 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.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCUnitRegistrationCommand.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCUnitRegistrationCommand.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCUnitRegistrationCommand.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCUnitRegistrationCommand.java index 0575e46d1..517517485 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCUnitRegistrationCommand.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCUnitRegistrationCommand.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; 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.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCUnitToUnitAnswerRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCUnitToUnitAnswerRequest.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCUnitToUnitAnswerRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCUnitToUnitAnswerRequest.java index 1a61ddce6..e10504c35 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCUnitToUnitAnswerRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCUnitToUnitAnswerRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,13 +18,13 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCUnitToUnitVoiceChannelUser.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCUnitToUnitVoiceChannelUser.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCUnitToUnitVoiceChannelUser.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCUnitToUnitVoiceChannelUser.java index 205db5cae..78ffa455e 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/lc/standard/LCUnitToUnitVoiceChannelUser.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/lc/standard/LCUnitToUnitVoiceChannelUser.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,13 +18,13 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.lc.standard; +package io.github.dsheirer.module.decode.p25.phase1.message.lc.standard; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/ldu/EncryptionSyncParameters.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/ldu/EncryptionSyncParameters.java similarity index 72% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/ldu/EncryptionSyncParameters.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/ldu/EncryptionSyncParameters.java index 847c601a1..5bdb9ecf0 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/ldu/EncryptionSyncParameters.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/ldu/EncryptionSyncParameters.java @@ -1,7 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.ldu; +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.ldu; +import io.github.dsheirer.audio.codec.mbe.IEncryptionSyncParameters; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier; import io.github.dsheirer.module.decode.p25.identifier.encryption.APCO25EncryptionKey; import java.util.ArrayList; @@ -10,7 +34,7 @@ /** * Encryption Sync Parameters from Logical Link Data Unit 2 voice frame. */ -public class EncryptionSyncParameters +public class EncryptionSyncParameters implements IEncryptionSyncParameters { private static final int[] MESSAGE_INDICATOR_1 = {0, 1, 2, 3, 4, 5, 6, 7}; private static final int[] MESSAGE_INDICATOR_2 = {8, 9, 10, 11, 12, 13, 14, 15}; @@ -27,7 +51,7 @@ public class EncryptionSyncParameters private BinaryMessage mMessage; private boolean mValid = true; private String mMessageIndicator; - private APCO25EncryptionKey mEncryptionKey; + private EncryptionKeyIdentifier mEncryptionKey; private List mIdentifiers; /** @@ -106,11 +130,12 @@ public String getMessageIndicator() return mMessageIndicator; } - public APCO25EncryptionKey getEncryptionKey() + public EncryptionKeyIdentifier getEncryptionKey() { if(mEncryptionKey == null) { - mEncryptionKey = APCO25EncryptionKey.create(getMessage().getInt(ALGORITHM_ID), getMessage().getInt(KEY_ID)); + mEncryptionKey = EncryptionKeyIdentifier.create(APCO25EncryptionKey.create(getMessage().getInt(ALGORITHM_ID), + getMessage().getInt(KEY_ID))); } return mEncryptionKey; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/ldu/LDU1Message.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/ldu/LDU1Message.java similarity index 85% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/ldu/LDU1Message.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/ldu/LDU1Message.java index 1d18872cb..b9efcdf6d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/ldu/LDU1Message.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/ldu/LDU1Message.java @@ -1,4 +1,24 @@ -package io.github.dsheirer.module.decode.p25.message.ldu; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.ldu; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.bits.CorrectedBinaryMessage; @@ -6,10 +26,10 @@ import io.github.dsheirer.edac.Hamming10; import io.github.dsheirer.edac.ReedSolomon_63_47_17; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWordFactory; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +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.phase1.message.lc.LinkControlWordFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -78,9 +98,9 @@ public LDU1Message(CorrectedBinaryMessage message, int nac, long timestamp) } @Override - public DataUnitID getDUID() + public P25P1DataUnitID getDUID() { - return DataUnitID.LOGICAL_LINK_DATA_UNIT_1; + return P25P1DataUnitID.LOGICAL_LINK_DATA_UNIT_1; } public LinkControlWord getLinkControlWord() diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/ldu/LDU2Message.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/ldu/LDU2Message.java similarity index 86% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/ldu/LDU2Message.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/ldu/LDU2Message.java index 45b29866e..4a5ef4936 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/ldu/LDU2Message.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/ldu/LDU2Message.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.ldu; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.ldu; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.edac.Hamming10; import io.github.dsheirer.edac.ReedSolomon_63_47_17; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,9 +72,9 @@ public LDU2Message(CorrectedBinaryMessage message, int nac, long timestamp) } @Override - public DataUnitID getDUID() + public P25P1DataUnitID getDUID() { - return DataUnitID.LOGICAL_LINK_DATA_UNIT_2; + return P25P1DataUnitID.LOGICAL_LINK_DATA_UNIT_2; } /** diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/ldu/LDUMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/ldu/LDUMessage.java similarity index 71% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/ldu/LDUMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/ldu/LDUMessage.java index bbb17d363..1ff5d7039 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/ldu/LDUMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/ldu/LDUMessage.java @@ -1,7 +1,27 @@ -package io.github.dsheirer.module.decode.p25.message.ldu; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.ldu; import io.github.dsheirer.bits.CorrectedBinaryMessage; -import io.github.dsheirer.module.decode.p25.message.P25Message; +import io.github.dsheirer.module.decode.p25.phase1.message.P25Message; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUHeader.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUHeader.java similarity index 98% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUHeader.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUHeader.java index 40316f25e..a45065890 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUHeader.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUHeader.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.bits.CorrectedBinaryMessage; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUHeaderFactory.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUHeaderFactory.java similarity index 85% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUHeaderFactory.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUHeaderFactory.java index 0d1379b57..98956e576 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUHeaderFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUHeaderFactory.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,13 +18,13 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.edac.CRCP25; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCHeader; -import io.github.dsheirer.module.decode.p25.message.pdu.packet.PacketHeader; -import io.github.dsheirer.module.decode.p25.message.pdu.response.ResponseHeader; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCHeader; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.PacketHeader; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.response.ResponseHeader; import io.github.dsheirer.module.decode.p25.reference.PDUFormat; public class PDUHeaderFactory diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUMessage.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUMessage.java index 36381bafb..037cde24d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUMessage.java @@ -17,15 +17,15 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +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.tsbk.Opcode; import io.github.dsheirer.module.decode.p25.reference.Direction; import io.github.dsheirer.module.decode.p25.reference.PDUFormat; import io.github.dsheirer.module.decode.p25.reference.ServiceAccessPoint; @@ -62,9 +62,9 @@ public PDUMessage(CorrectedBinaryMessage message, int nac, long timestamp) } @Override - public DataUnitID getDUID() + public P25P1DataUnitID getDUID() { - return DataUnitID.PACKET_DATA_UNIT; + return P25P1DataUnitID.PACKET_DATA_UNIT; } protected String getMessageStub() diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUMessageFactory.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUMessageFactory.java similarity index 70% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUMessageFactory.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUMessageFactory.java index 60858a7b8..3c2c4e901 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUMessageFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUMessageFactory.java @@ -1,70 +1,78 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25.message.pdu; + */ +package io.github.dsheirer.module.decode.p25.phase1.message.pdu; import io.github.dsheirer.alias.AliasList; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.edac.trellis.ViterbiDecoder_1_2_P25; -import io.github.dsheirer.module.decode.p25.P25Interleave; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCHeader; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCAuthenticationQuery; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCAuthenticationResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCCallAlertRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCGroupAffiliationRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCIndividualDataServiceRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCLocationRegistrationRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCMessageUpdateRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCRoamingAddressRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCStatusQueryRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCStatusQueryResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCStatusUpdateRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCUnitAcknowledgeResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCUnitToUnitVoiceServiceAnswerResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp.AMBTCUnitToUnitVoiceServiceRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCAdjacentStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCCallAlert; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCGroupAffiliationQuery; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCGroupAffiliationResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCGroupDataChannelGrant; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCGroupVoiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCIndividualDataChannelGrant; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCMessageUpdate; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCProtectionParameterBroadcast; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCRoamingAddressResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCRoamingAddressUpdate; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCStatusQuery; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCStatusUpdate; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCTelephoneInterconnectChannelGrant; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCTelephoneInterconnectChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCUnitRegistrationResponse; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCUnitToUnitAnswerRequest; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCUnitToUnitVoiceServiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp.AMBTCUnitToUnitVoiceServiceChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.message.pdu.block.ConfirmedDataBlock; -import io.github.dsheirer.module.decode.p25.message.pdu.block.DataBlock; -import io.github.dsheirer.module.decode.p25.message.pdu.block.UnconfirmedDataBlock; -import io.github.dsheirer.module.decode.p25.message.pdu.packet.PacketHeader; -import io.github.dsheirer.module.decode.p25.message.pdu.packet.PacketMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp.SNDCPPacketMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.response.ResponseMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.umbtc.isp.UMBTCTelephoneInterconnectRequestExplicitDialing; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1Interleave; +import io.github.dsheirer.module.decode.p25.phase1.message.P25Message; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCHeader; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCAuthenticationQuery; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCAuthenticationResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCCallAlertRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCGroupAffiliationRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCIndividualDataServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCLocationRegistrationRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCMessageUpdateRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCRoamingAddressRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCStatusQueryRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCStatusQueryResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCStatusUpdateRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCUnitAcknowledgeResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCUnitToUnitVoiceServiceAnswerResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp.AMBTCUnitToUnitVoiceServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCAdjacentStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCCallAlert; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCGroupAffiliationQuery; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCGroupAffiliationResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCGroupDataChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCGroupVoiceChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCIndividualDataChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCMessageUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCNetworkStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCProtectionParameterBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCRFSSStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCRoamingAddressResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCRoamingAddressUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCStatusQuery; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCStatusUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCTelephoneInterconnectChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCTelephoneInterconnectChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCUnitRegistrationResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCUnitToUnitAnswerRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCUnitToUnitVoiceServiceChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp.AMBTCUnitToUnitVoiceServiceChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.ConfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.DataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.PacketHeader; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.PacketMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPPacketMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.response.ResponseMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.umbtc.isp.UMBTCTelephoneInterconnectRequestExplicitDialing; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; import io.github.dsheirer.module.decode.p25.reference.PDUFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -85,7 +93,7 @@ public static PDUSequence createPacketSequence(int nac, long timestamp, Correcte { //Get deinterleaved header chunk BitSet interleaved = correctedBinaryMessage.get(PDU0_BEGIN, PDU0_END); - CorrectedBinaryMessage deinterleaved = P25Interleave.deinterleaveChunk(P25Interleave.DATA_DEINTERLEAVE, interleaved); + CorrectedBinaryMessage deinterleaved = P25P1Interleave.deinterleaveChunk(P25P1Interleave.DATA_DEINTERLEAVE, interleaved); //Decode 1/2 rate trellis encoded PDU header CorrectedBinaryMessage viterbiDecoded = VITERBI_HALF_RATE_DECODER.decode(deinterleaved); @@ -127,7 +135,7 @@ public static P25Message create(PDUSequence pduSequence, int nac, long timestamp */ public static DataBlock createConfirmedDataBlock(CorrectedBinaryMessage interleaved) { - CorrectedBinaryMessage deinterleaved = P25Interleave.deinterleaveChunk(P25Interleave.DATA_DEINTERLEAVE, interleaved); + CorrectedBinaryMessage deinterleaved = P25P1Interleave.deinterleaveChunk(P25P1Interleave.DATA_DEINTERLEAVE, interleaved); return new ConfirmedDataBlock(deinterleaved); } @@ -136,7 +144,7 @@ public static DataBlock createConfirmedDataBlock(CorrectedBinaryMessage interlea */ public static DataBlock createUnconfirmedDataBlock(CorrectedBinaryMessage interleaved) { - CorrectedBinaryMessage deinterleaved = P25Interleave.deinterleaveChunk(P25Interleave.DATA_DEINTERLEAVE, interleaved); + CorrectedBinaryMessage deinterleaved = P25P1Interleave.deinterleaveChunk(P25P1Interleave.DATA_DEINTERLEAVE, interleaved); return new UnconfirmedDataBlock(deinterleaved); } @@ -244,8 +252,12 @@ public static P25Message createAMBTC(PDUSequence pduSequence, int nac, long time return new AMBTCIndividualDataChannelGrant(pduSequence, nac, timestamp); case OSP_MESSAGE_UPDATE: return new AMBTCMessageUpdate(pduSequence, nac, timestamp); + case OSP_NETWORK_STATUS_BROADCAST: + return new AMBTCNetworkStatusBroadcast(pduSequence, nac, timestamp); case OSP_PROTECTION_PARAMETER_BROADCAST: return new AMBTCProtectionParameterBroadcast(pduSequence, nac, timestamp); + case OSP_RFSS_STATUS_BROADCAST: + return new AMBTCRFSSStatusBroadcast(pduSequence, nac, timestamp); case OSP_ROAMING_ADDRESS_UPDATE: return new AMBTCRoamingAddressUpdate(pduSequence, nac, timestamp); case OSP_ROAMING_ADDRESS_COMMAND: @@ -299,7 +311,7 @@ public static P25Message createUMBTC(PDUSequence pduSequence, int nac, long time } @Deprecated - public static PDUMessage getMessage(BinaryMessage message, DataUnitID duid, AliasList aliasList) + public static PDUMessage getMessage(BinaryMessage message, P25P1DataUnitID duid, AliasList aliasList) { PDUFormat format = PDUFormat.fromValue(message.getInt(PDUMessage.FORMAT)); diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUSequence.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUSequence.java similarity index 81% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUSequence.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUSequence.java index d22b253c0..d47162f02 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/PDUSequence.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUSequence.java @@ -1,22 +1,26 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * sdrtrunk + * 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 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. + * 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 - * - ******************************************************************************/ -package io.github.dsheirer.module.decode.p25.message.pdu; + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * ***************************************************************************** + */ +package io.github.dsheirer.module.decode.p25.phase1.message.pdu; import io.github.dsheirer.message.IBitErrorProvider; -import io.github.dsheirer.module.decode.p25.message.pdu.block.DataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.DataBlock; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUSequenceMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUSequenceMessage.java new file mode 100644 index 000000000..714bf84ef --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/PDUSequenceMessage.java @@ -0,0 +1,63 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.pdu; + +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 java.util.Collections; +import java.util.List; + +public class PDUSequenceMessage extends P25Message +{ + private PDUSequence mPDUSequence; + + public PDUSequenceMessage(PDUSequence PDUSequence, int nac, long timestamp) + { + super(null, nac, timestamp); + mPDUSequence = PDUSequence; + } + + public PDUSequence getPDUSequence() + { + return mPDUSequence; + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getPDUSequence().toString()); + return sb.toString(); + } + + @Override + public P25P1DataUnitID getDUID() + { + return P25P1DataUnitID.PACKET_DATA_UNIT; + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/AMBTCHeader.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/AMBTCHeader.java similarity index 91% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/AMBTCHeader.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/AMBTCHeader.java index 3012291e7..3f3fe38b6 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/AMBTCHeader.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/AMBTCHeader.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -17,12 +17,12 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.module.decode.p25.P25Utils; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUHeader; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUHeader; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; import io.github.dsheirer.module.decode.p25.reference.ServiceAccessPoint; import io.github.dsheirer.module.decode.p25.reference.Vendor; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/AMBTCMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/AMBTCMessage.java similarity index 89% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/AMBTCMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/AMBTCMessage.java index 8575c0c4b..6228d0d86 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/AMBTCMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/AMBTCMessage.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,18 +18,18 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.message.IBitErrorProvider; import io.github.dsheirer.module.decode.p25.P25Utils; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.block.DataBlock; -import io.github.dsheirer.module.decode.p25.message.pdu.block.UnconfirmedDataBlock; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +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.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.DataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; import java.util.List; @@ -84,9 +84,9 @@ public UnconfirmedDataBlock getDataBlock(int index) @Override - public DataUnitID getDUID() + public P25P1DataUnitID getDUID() { - return DataUnitID.ALTERNATE_MULTI_BLOCK_TRUNKING_CONTROL; + return P25P1DataUnitID.ALTERNATE_MULTI_BLOCK_TRUNKING_CONTROL; } /** diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCAuthenticationQuery.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCAuthenticationQuery.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCAuthenticationQuery.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCAuthenticationQuery.java index f8dbfd4c3..3ca40273b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCAuthenticationQuery.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCAuthenticationQuery.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCAuthenticationResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCAuthenticationResponse.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCAuthenticationResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCAuthenticationResponse.java index 3dd38c771..4abcaeefd 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCAuthenticationResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCAuthenticationResponse.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCCallAlertRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCCallAlertRequest.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCCallAlertRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCCallAlertRequest.java index 900e7cf88..f7b0a31e2 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCCallAlertRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCCallAlertRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; 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.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCGroupAffiliationRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCGroupAffiliationRequest.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCGroupAffiliationRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCGroupAffiliationRequest.java index 8ebe11b28..31d7929e4 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCGroupAffiliationRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCGroupAffiliationRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCIndividualDataServiceRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCIndividualDataServiceRequest.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCIndividualDataServiceRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCIndividualDataServiceRequest.java index 6f1240fdc..3a10a9190 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCIndividualDataServiceRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCIndividualDataServiceRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCLocationRegistrationRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCLocationRegistrationRequest.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCLocationRegistrationRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCLocationRegistrationRequest.java index 4c44aa3be..f5e2147df 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCLocationRegistrationRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCLocationRegistrationRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra; @@ -27,8 +27,8 @@ import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25IdentifierTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCMessageUpdateRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCMessageUpdateRequest.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCMessageUpdateRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCMessageUpdateRequest.java index d63b6ab8d..e74ff0140 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCMessageUpdateRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCMessageUpdateRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.APCO25System; @@ -26,8 +26,8 @@ import io.github.dsheirer.module.decode.p25.identifier.message.APCO25ShortDataMessage; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCRoamingAddressRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCRoamingAddressRequest.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCRoamingAddressRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCRoamingAddressRequest.java index 9603b2eac..acacadd3a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCRoamingAddressRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCRoamingAddressRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; 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.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCStatusQueryRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCStatusQueryRequest.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCStatusQueryRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCStatusQueryRequest.java index 8d48a5532..4a2e8100a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCStatusQueryRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCStatusQueryRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCStatusQueryResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCStatusQueryResponse.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCStatusQueryResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCStatusQueryResponse.java index 9e7134b7e..1bba3deaf 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCStatusQueryResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCStatusQueryResponse.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.APCO25System; @@ -27,8 +27,8 @@ import io.github.dsheirer.module.decode.p25.identifier.status.APCO25UserStatus; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCStatusUpdateRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCStatusUpdateRequest.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCStatusUpdateRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCStatusUpdateRequest.java index 457b5f3dd..d9abf32cd 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCStatusUpdateRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCStatusUpdateRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.APCO25System; @@ -27,8 +27,8 @@ import io.github.dsheirer.module.decode.p25.identifier.status.APCO25UserStatus; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCUnitAcknowledgeResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCUnitAcknowledgeResponse.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCUnitAcknowledgeResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCUnitAcknowledgeResponse.java index 4bf86a54a..f37f79634 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCUnitAcknowledgeResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCUnitAcknowledgeResponse.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,16 +18,16 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; import io.github.dsheirer.module.decode.p25.reference.Direction; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCUnitToUnitVoiceServiceAnswerResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCUnitToUnitVoiceServiceAnswerResponse.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCUnitToUnitVoiceServiceAnswerResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCUnitToUnitVoiceServiceAnswerResponse.java index 0dfd085fd..c2f3a1d34 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCUnitToUnitVoiceServiceAnswerResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCUnitToUnitVoiceServiceAnswerResponse.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import io.github.dsheirer.module.decode.p25.reference.AnswerResponse; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCUnitToUnitVoiceServiceRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCUnitToUnitVoiceServiceRequest.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCUnitToUnitVoiceServiceRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCUnitToUnitVoiceServiceRequest.java index d70f63967..48436bdf2 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/isp/AMBTCUnitToUnitVoiceServiceRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/isp/AMBTCUnitToUnitVoiceServiceRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.isp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCAdjacentStatusBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCAdjacentStatusBroadcast.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCAdjacentStatusBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCAdjacentStatusBroadcast.java index 54bb97169..cf61f3875 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCAdjacentStatusBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCAdjacentStatusBroadcast.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.identifier.Identifier; @@ -28,10 +28,10 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25System; 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.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.block.UnconfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCCallAlert.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCCallAlert.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCCallAlert.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCCallAlert.java index f623bc959..f535772e0 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCCallAlert.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCCallAlert.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCGroupAffiliationQuery.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCGroupAffiliationQuery.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCGroupAffiliationQuery.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCGroupAffiliationQuery.java index a44cf8e43..ff9fbe657 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCGroupAffiliationQuery.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCGroupAffiliationQuery.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCGroupAffiliationResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCGroupAffiliationResponse.java similarity index 96% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCGroupAffiliationResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCGroupAffiliationResponse.java index 4c4e640ef..2ec275730 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCGroupAffiliationResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCGroupAffiliationResponse.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.APCO25System; @@ -26,8 +26,8 @@ import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25AnnouncementTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCGroupDataChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCGroupDataChannelGrant.java similarity index 92% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCGroupDataChannelGrant.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCGroupDataChannelGrant.java index b3b2dd12e..99d1c62e1 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCGroupDataChannelGrant.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCGroupDataChannelGrant.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.identifier.Identifier; @@ -26,10 +26,10 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.block.UnconfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCGroupVoiceChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCGroupVoiceChannelGrant.java similarity index 92% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCGroupVoiceChannelGrant.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCGroupVoiceChannelGrant.java index fe1165010..73688e489 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCGroupVoiceChannelGrant.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCGroupVoiceChannelGrant.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.identifier.Identifier; @@ -26,10 +26,10 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.block.UnconfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCIndividualDataChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCIndividualDataChannelGrant.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCIndividualDataChannelGrant.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCIndividualDataChannelGrant.java index 07583c659..c6874c2aa 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCIndividualDataChannelGrant.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCIndividualDataChannelGrant.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.identifier.Identifier; @@ -28,10 +28,10 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.block.UnconfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCMessageUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCMessageUpdate.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCMessageUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCMessageUpdate.java index ccf2e62da..e9480e865 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCMessageUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCMessageUpdate.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.APCO25System; @@ -26,8 +26,8 @@ import io.github.dsheirer.module.decode.p25.identifier.message.APCO25ShortDataMessage; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCNetworkStatusBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCNetworkStatusBroadcast.java new file mode 100644 index 000000000..e5c53b3cf --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCNetworkStatusBroadcast.java @@ -0,0 +1,211 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; + +import io.github.dsheirer.channel.IChannelDescriptor; +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.channel.APCO25Channel; +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.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; + +import java.util.ArrayList; +import java.util.List; + +/** + * Network Status Broadcast + * + * TODO: this parser class is incomplete at the moment ... + */ +public class AMBTCNetworkStatusBroadcast extends AMBTCMessage implements IFrequencyBandReceiver +{ + + // private static final int[] HEADER_LRA = {24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] HEADER_SYSTEM = {36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + // private static final int[] HEADER_RFSS = {64, 65, 66, 67, 68, 69, 70, 71}; + // private static final int[] HEADER_SITE = {72, 73, 74, 75, 76, 77, 78, 79}; + private static final int[] BLOCK_0_WACN = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + private static final int[] BLOCK_0_DOWNLINK_FREQUENCY_BAND = {24, 25, 26, 27}; + private static final int[] BLOCK_0_DOWNLINK_CHANNEL_NUMBER = {28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; + private static final int[] BLOCK_0_UPLINK_FREQUENCY_BAND = {40, 41, 42, 43}; + private static final int[] BLOCK_0_UPLINK_CHANNEL_NUMBER = {44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55}; + private static final int[] BLOCK_0_SYSTEM_SERVICE_CLASS = {56, 57, 58, 59, 60, 61, 62, 63}; + + private ScrambleParameters mScrambleParameters; + private Identifier mWacn; + private Identifier mSystem; + private IChannelDescriptor mChannel; + private List mIdentifiers; + private List mChannels; + private SystemServiceClass mSystemServiceClass; + + public AMBTCNetworkStatusBroadcast(PDUSequence PDUSequence, int nac, long timestamp) + { + super(PDUSequence, nac, timestamp); + + setValid(hasDataBlock(0)); + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getMessageStub()); + sb.append(" WACN:").append(getWacn()); + sb.append(" SYSTEM:").append(getSystem()); + sb.append(" CHAN:").append(getChannel()); + sb.append(" SERVICES:").append(getSystemServiceClass()); + return sb.toString(); + } + + public SystemServiceClass getSystemServiceClass() + { + if(mSystemServiceClass == null && hasDataBlock(0)) + { + if(hasDataBlock(0)) + { + mSystemServiceClass = new SystemServiceClass(getDataBlock(0).getMessage().getInt(BLOCK_0_SYSTEM_SERVICE_CLASS)); + } + else + { + mSystemServiceClass = new SystemServiceClass(0); + } + } + + return mSystemServiceClass; + } + + public ScrambleParameters getScrambleParameters() + { + if(mScrambleParameters == null) + { + int wacn = (int)getWacn().getValue(); + int system = (int)getSystem().getValue(); + int nac = (int)getNAC().getValue(); + + mScrambleParameters = new ScrambleParameters(wacn, system, nac); + } + + return mScrambleParameters; + } + + public Identifier getSystem() + { + if(mSystem == null) + { + mSystem = APCO25System.create(getHeader().getMessage().getInt(HEADER_SYSTEM)); + } + + return mSystem; + } + + public Identifier getWacn() + { + if(mWacn == null && hasDataBlock(0)) + { + mWacn = APCO25Wacn.create(getDataBlock(0).getMessage().getInt(BLOCK_0_WACN)); + } + + return mWacn; + } + + public boolean isExtendedChannel() + { + return hasDataBlock(0) && + (getDataBlock(0).getMessage().getInt(BLOCK_0_DOWNLINK_CHANNEL_NUMBER) != + getDataBlock(0).getMessage().getInt(BLOCK_0_UPLINK_CHANNEL_NUMBER)); + } + + /** + * Control channel. + */ + public IChannelDescriptor getChannel() + { + if(mChannel == null && hasDataBlock(0)) + { + if(hasDataBlock(0)) + { + UnconfirmedDataBlock block = getDataBlock(0); + + if(isExtendedChannel()) + { + mChannel = APCO25ExplicitChannel.create(block.getMessage().getInt(BLOCK_0_DOWNLINK_FREQUENCY_BAND), + block.getMessage().getInt(BLOCK_0_DOWNLINK_CHANNEL_NUMBER), + block.getMessage().getInt(BLOCK_0_UPLINK_FREQUENCY_BAND), + block.getMessage().getInt(BLOCK_0_UPLINK_CHANNEL_NUMBER)); + } + else + { + mChannel = APCO25Channel.create(block.getMessage().getInt(BLOCK_0_DOWNLINK_FREQUENCY_BAND), + block.getMessage().getInt(BLOCK_0_DOWNLINK_CHANNEL_NUMBER)); + } + } + else + { + mChannel = APCO25Channel.create(-1, 0); + } + } + + return mChannel; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + if(getWacn() != null) + { + mIdentifiers.add(getWacn()); + } + if(getSystem() != null) + { + mIdentifiers.add(getSystem()); + } + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + if(mChannels == null) + { + mChannels = new ArrayList<>(); + + if(getChannel() != null) + { + mChannels.add(getChannel()); + } + } + + return mChannels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCProtectionParameterBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCProtectionParameterBroadcast.java similarity index 76% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCProtectionParameterBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCProtectionParameterBroadcast.java index bd51e2e9a..e3044bb48 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCProtectionParameterBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCProtectionParameterBroadcast.java @@ -1,30 +1,33 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; 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.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; @@ -95,8 +98,8 @@ public Identifier getEncryptionKey() { if(mEncryptionKey == null && hasDataBlock(0)) { - mEncryptionKey = APCO25EncryptionKey.create(getHeader().getMessage().getInt(HEADER_ALGORITHM_ID), - getDataBlock(0).getMessage().getInt(BLOCK_0_KEY_ID)); + mEncryptionKey = EncryptionKeyIdentifier.create(APCO25EncryptionKey.create(getHeader().getMessage().getInt(HEADER_ALGORITHM_ID), + getDataBlock(0).getMessage().getInt(BLOCK_0_KEY_ID))); } return mEncryptionKey; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCRFSSStatusBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCRFSSStatusBroadcast.java new file mode 100644 index 000000000..ec38bad3e --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCRFSSStatusBroadcast.java @@ -0,0 +1,205 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; + +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; +import io.github.dsheirer.module.decode.p25.identifier.APCO25System; +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.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; + +import java.util.ArrayList; +import java.util.List; + +/** + * RFSS Status Broadcast + * + * TODO: this parser class is incomplete at the moment ... + */ +public class AMBTCRFSSStatusBroadcast extends AMBTCMessage implements IFrequencyBandReceiver +{ + + private static final int[] HEADER_LRA = {24, 25, 26, 27, 28, 29, 30, 31}; + private static final int HEADER_ACTIVE_NETWORK_CONNECTION_TO_RFSS_CONTROLLER_FLAG = 35; + private static final int[] HEADER_SYSTEM = {36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + private static final int[] BLOCK_0_RFSS = {0, 1, 2, 3, 4, 5, 6, 7}; + private static final int[] BLOCK_0_SITE = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] BLOCK_0_DOWNLINK_FREQUENCY_BAND = {16, 17, 18, 19}; + private static final int[] BLOCK_0_DOWNLINK_CHANNEL_NUMBER = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] BLOCK_0_UPLINK_FREQUENCY_BAND = {32, 33, 34, 35}; + private static final int[] BLOCK_0_UPLINK_CHANNEL_NUMBER = {36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + + private Identifier mLra; + private Identifier mSystem; + private Identifier mRfss; + private Identifier mSite; + private IChannelDescriptor mChannel; + private List mIdentifiers; + private List mChannels; + + public AMBTCRFSSStatusBroadcast(PDUSequence PDUSequence, int nac, long timestamp) + { + super(PDUSequence, nac, timestamp); + + setValid(hasDataBlock(0)); + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getMessageStub()); + sb.append(" SYSTEM:").append(getSystem()); + sb.append(" SITE:").append(getSite()); + if(isActiveNetworkConnectionToRfssControllerSite()) + { + sb.append(" ACTIVE NETWORK CONNECTION"); + } + sb.append(" RFSS:").append(getRFSS()); + sb.append(" LRA:").append(getLRA()); + sb.append(" CHAN:").append(getChannel()); + return sb.toString(); + } + + public Identifier getLRA() + { + if(mLra == null) + { + mLra = APCO25Lra.create(getHeader().getMessage().getInt(HEADER_LRA)); + } + + return mLra; + } + + public Identifier getSystem() + { + if(mSystem == null) + { + mSystem = APCO25System.create(getHeader().getMessage().getInt(HEADER_SYSTEM)); + } + + return mSystem; + } + + public Identifier getRFSS() + { + if(mRfss == null && hasDataBlock(0)) + { + mRfss = APCO25Rfss.create(getDataBlock(0).getMessage().getInt(BLOCK_0_RFSS)); + } + + return mRfss; + } + + /** + * Indicates if the site has an active network connection to the RFSS controller + */ + public boolean isActiveNetworkConnectionToRfssControllerSite() + { + return getHeader().getMessage().get(HEADER_ACTIVE_NETWORK_CONNECTION_TO_RFSS_CONTROLLER_FLAG); + } + + public Identifier getSite() + { + if(mSite == null && hasDataBlock(0)) + { + mSite = APCO25Site.create(getDataBlock(0).getMessage().getInt(BLOCK_0_SITE)); + } + + return mSite; + } + + /** + * Control channel. + */ + public IChannelDescriptor getChannel() + { + if(mChannel == null && hasDataBlock(0)) + { + if(hasDataBlock(0)) + { + UnconfirmedDataBlock block = getDataBlock(0); + + mChannel = APCO25ExplicitChannel.create(block.getMessage().getInt(BLOCK_0_DOWNLINK_FREQUENCY_BAND), + block.getMessage().getInt(BLOCK_0_DOWNLINK_CHANNEL_NUMBER), + block.getMessage().getInt(BLOCK_0_UPLINK_FREQUENCY_BAND), + block.getMessage().getInt(BLOCK_0_UPLINK_CHANNEL_NUMBER)); + } + else + { + mChannel = APCO25Channel.create(-1, 0); + } + } + + return mChannel; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + if(getLRA() != null) + { + mIdentifiers.add(getLRA()); + } + if(getSystem() != null) + { + mIdentifiers.add(getSystem()); + } + if(getRFSS() != null) + { + mIdentifiers.add(getRFSS()); + } + if(getSite() != null) + { + mIdentifiers.add(getSite()); + } + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + if(mChannels == null) + { + mChannels = new ArrayList<>(); + + if(getChannel() != null) + { + mChannels.add(getChannel()); + } + } + + return mChannels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCRoamingAddressResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCRoamingAddressResponse.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCRoamingAddressResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCRoamingAddressResponse.java index 4afb047f7..d6f9450f8 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCRoamingAddressResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCRoamingAddressResponse.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; 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.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCRoamingAddressUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCRoamingAddressUpdate.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCRoamingAddressUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCRoamingAddressUpdate.java index a3faaea9e..3d37c1c85 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCRoamingAddressUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCRoamingAddressUpdate.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; 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.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCStatusQuery.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCStatusQuery.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCStatusQuery.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCStatusQuery.java index fe300c246..51036337e 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCStatusQuery.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCStatusQuery.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCStatusUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCStatusUpdate.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCStatusUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCStatusUpdate.java index 826d6aaa3..c7627ba85 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCStatusUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCStatusUpdate.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.APCO25System; @@ -27,8 +27,8 @@ import io.github.dsheirer.module.decode.p25.identifier.status.APCO25UserStatus; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCTelephoneInterconnectChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCTelephoneInterconnectChannelGrant.java similarity index 92% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCTelephoneInterconnectChannelGrant.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCTelephoneInterconnectChannelGrant.java index 46467cd82..922cb1d2d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCTelephoneInterconnectChannelGrant.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCTelephoneInterconnectChannelGrant.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,17 +18,17 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; 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.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.block.UnconfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCTelephoneInterconnectChannelGrantUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCTelephoneInterconnectChannelGrantUpdate.java similarity index 92% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCTelephoneInterconnectChannelGrantUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCTelephoneInterconnectChannelGrantUpdate.java index a54b7623f..c9499c741 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCTelephoneInterconnectChannelGrantUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCTelephoneInterconnectChannelGrantUpdate.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,17 +18,17 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; 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.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.block.UnconfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCUnitRegistrationResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCUnitRegistrationResponse.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCUnitRegistrationResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCUnitRegistrationResponse.java index dfccbb5ad..b41cff902 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCUnitRegistrationResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCUnitRegistrationResponse.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import io.github.dsheirer.module.decode.p25.reference.Response; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCUnitToUnitAnswerRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCUnitToUnitAnswerRequest.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCUnitToUnitAnswerRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCUnitToUnitAnswerRequest.java index 432c4ccec..69fca6c0f 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCUnitToUnitAnswerRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCUnitToUnitAnswerRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCUnitToUnitVoiceServiceChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCUnitToUnitVoiceServiceChannelGrant.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCUnitToUnitVoiceServiceChannelGrant.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCUnitToUnitVoiceServiceChannelGrant.java index b76327b99..810f83967 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCUnitToUnitVoiceServiceChannelGrant.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCUnitToUnitVoiceServiceChannelGrant.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.identifier.Identifier; @@ -28,10 +28,10 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.block.UnconfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCUnitToUnitVoiceServiceChannelGrantUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCUnitToUnitVoiceServiceChannelGrantUpdate.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCUnitToUnitVoiceServiceChannelGrantUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCUnitToUnitVoiceServiceChannelGrantUpdate.java index 72b197bc8..2c093bba0 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/ambtc/osp/AMBTCUnitToUnitVoiceServiceChannelGrantUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/ambtc/osp/AMBTCUnitToUnitVoiceServiceChannelGrantUpdate.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.ambtc.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.osp; import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.identifier.Identifier; @@ -28,10 +28,10 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.ambtc.AMBTCMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.block.UnconfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.ambtc.AMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/block/ConfirmedDataBlock.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/block/ConfirmedDataBlock.java similarity index 96% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/block/ConfirmedDataBlock.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/block/ConfirmedDataBlock.java index 2b7cd345f..2d1c91271 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/block/ConfirmedDataBlock.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/block/ConfirmedDataBlock.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.block; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.block; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.bits.CorrectedBinaryMessage; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/block/DataBlock.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/block/DataBlock.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/block/DataBlock.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/block/DataBlock.java index 0e72a8068..390457837 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/block/DataBlock.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/block/DataBlock.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -17,7 +17,7 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.block; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.block; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.message.IBitErrorProvider; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/block/UnconfirmedDataBlock.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/block/UnconfirmedDataBlock.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/block/UnconfirmedDataBlock.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/block/UnconfirmedDataBlock.java index 914211310..c98da4b93 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/block/UnconfirmedDataBlock.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/block/UnconfirmedDataBlock.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.block; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.block; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.edac.trellis.ViterbiDecoder_1_2_P25; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/PacketHeader.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/PacketHeader.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/PacketHeader.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/PacketHeader.java index f2ae0131e..fd8343b55 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/PacketHeader.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/PacketHeader.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -17,10 +17,10 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.packet; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet; import io.github.dsheirer.bits.CorrectedBinaryMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUHeader; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUHeader; import io.github.dsheirer.module.decode.p25.reference.ServiceAccessPoint; public class PacketHeader extends PDUHeader diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/PacketMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/PacketMessage.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/PacketMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/PacketMessage.java index 55b52dd03..4b4a4e105 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/PacketMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/PacketMessage.java @@ -18,19 +18,19 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.packet; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.ip.IPacket; import io.github.dsheirer.module.decode.ip.PacketMessageFactory; import io.github.dsheirer.module.decode.ip.ipv4.IPV4Packet; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.block.ConfirmedDataBlock; -import io.github.dsheirer.module.decode.p25.message.pdu.block.DataBlock; -import io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp.SNDCPPacketHeader; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +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.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.ConfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.DataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp.SNDCPPacketHeader; import io.github.dsheirer.module.decode.p25.reference.IPHeaderCompression; import io.github.dsheirer.module.decode.p25.reference.UDPHeaderCompression; @@ -251,9 +251,9 @@ public BinaryMessage getPayloadMessage() } @Override - public DataUnitID getDUID() + public P25P1DataUnitID getDUID() { - return DataUnitID.IP_PACKET_DATA; + return P25P1DataUnitID.IP_PACKET_DATA; } @Override diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/ActivateTdsContextAccept.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/ActivateTdsContextAccept.java similarity index 98% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/ActivateTdsContextAccept.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/ActivateTdsContextAccept.java index b69eadb43..90bfec9d5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/ActivateTdsContextAccept.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/ActivateTdsContextAccept.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/ActivateTdsContextReject.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/ActivateTdsContextReject.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/ActivateTdsContextReject.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/ActivateTdsContextReject.java index 7afedc6a4..a4c7624ca 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/ActivateTdsContextReject.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/ActivateTdsContextReject.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/ActivateTdsContextRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/ActivateTdsContextRequest.java similarity index 98% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/ActivateTdsContextRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/ActivateTdsContextRequest.java index 19dd5bdd2..644259f36 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/ActivateTdsContextRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/ActivateTdsContextRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/DeActivateTdsContextRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/DeActivateTdsContextRequest.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/DeActivateTdsContextRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/DeActivateTdsContextRequest.java index 2d86fc38c..1dbaf615a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/DeActivateTdsContextRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/DeActivateTdsContextRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.identifier.Identifier; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/SNDCPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/SNDCPMessage.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/SNDCPMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/SNDCPMessage.java index adfef6e8d..6aa560c9d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/SNDCPMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/SNDCPMessage.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.module.decode.p25.reference.PDUType; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/SNDCPMessageFactory.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/SNDCPMessageFactory.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/SNDCPMessageFactory.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/SNDCPMessageFactory.java index ed4c633ed..51a42a180 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/SNDCPMessageFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/SNDCPMessageFactory.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.module.decode.p25.reference.PDUType; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/SNDCPPacketHeader.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/SNDCPPacketHeader.java similarity index 96% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/SNDCPPacketHeader.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/SNDCPPacketHeader.java index f191f0f36..6fd1eb370 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/SNDCPPacketHeader.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/SNDCPPacketHeader.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.module.decode.ip.Header; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/SNDCPPacketMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/SNDCPPacketMessage.java similarity index 80% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/SNDCPPacketMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/SNDCPPacketMessage.java index aba6e2f1a..eecfba365 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/packet/sndcp/SNDCPPacketMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/packet/sndcp/SNDCPPacketMessage.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,11 +18,11 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.packet.sndcp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.sndcp; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.packet.PacketMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.PacketMessage; public class SNDCPPacketMessage extends PacketMessage { @@ -53,9 +53,9 @@ public String toString() } @Override - public DataUnitID getDUID() + public P25P1DataUnitID getDUID() { - return DataUnitID.SUBNETWORK_DEPENDENT_CONVERGENCE_PROTOCOL; + return P25P1DataUnitID.SUBNETWORK_DEPENDENT_CONVERGENCE_PROTOCOL; } public SNDCPMessage getSNDCPMessage() diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/response/ResponseHeader.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/response/ResponseHeader.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/response/ResponseHeader.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/response/ResponseHeader.java index 4958ec9e6..f2fb75826 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/response/ResponseHeader.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/response/ResponseHeader.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -17,10 +17,10 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.response; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.response; import io.github.dsheirer.bits.CorrectedBinaryMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUHeader; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUHeader; import io.github.dsheirer.module.decode.p25.reference.PacketResponse; import io.github.dsheirer.module.decode.p25.reference.Vendor; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/response/ResponseMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/response/ResponseMessage.java similarity index 92% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/response/ResponseMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/response/ResponseMessage.java index 41fd34659..81482be87 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/response/ResponseMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/response/ResponseMessage.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.response; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.response; import io.github.dsheirer.bits.BinaryMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequenceMessage; -import io.github.dsheirer.module.decode.p25.message.pdu.block.DataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequenceMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.DataBlock; import io.github.dsheirer.module.decode.p25.reference.PacketResponse; import java.util.ArrayList; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/umbtc/UMBTCHeader.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/umbtc/UMBTCHeader.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/umbtc/UMBTCHeader.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/umbtc/UMBTCHeader.java index 57f237bf6..38dcc5aaa 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/umbtc/UMBTCHeader.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/umbtc/UMBTCHeader.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -17,11 +17,11 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.umbtc; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.umbtc; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.module.decode.p25.P25Utils; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUHeader; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUHeader; import io.github.dsheirer.module.decode.p25.reference.ServiceAccessPoint; import io.github.dsheirer.module.decode.p25.reference.Vendor; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/umbtc/UMBTCMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/umbtc/UMBTCMessage.java similarity index 85% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/umbtc/UMBTCMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/umbtc/UMBTCMessage.java index 534e0c62c..e29ff61da 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/umbtc/UMBTCMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/umbtc/UMBTCMessage.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,17 +18,17 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.umbtc; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.umbtc; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.message.IBitErrorProvider; import io.github.dsheirer.module.decode.p25.P25Utils; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.block.DataBlock; -import io.github.dsheirer.module.decode.p25.message.pdu.block.UnconfirmedDataBlock; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +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.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.DataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.block.UnconfirmedDataBlock; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; import java.util.List; @@ -92,9 +92,9 @@ public UnconfirmedDataBlock getDataBlock(int index) @Override - public DataUnitID getDUID() + public P25P1DataUnitID getDUID() { - return DataUnitID.UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL; + return P25P1DataUnitID.UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL; } /** diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/umbtc/isp/UMBTCTelephoneInterconnectRequestExplicitDialing.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/umbtc/isp/UMBTCTelephoneInterconnectRequestExplicitDialing.java similarity index 94% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/umbtc/isp/UMBTCTelephoneInterconnectRequestExplicitDialing.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/umbtc/isp/UMBTCTelephoneInterconnectRequestExplicitDialing.java index 9cc67e263..33cbbe7a3 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/pdu/umbtc/isp/UMBTCTelephoneInterconnectRequestExplicitDialing.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/pdu/umbtc/isp/UMBTCTelephoneInterconnectRequestExplicitDialing.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.pdu.umbtc.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.pdu.umbtc.isp; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.message.IBitErrorProvider; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.telephone.APCO25TelephoneNumber; -import io.github.dsheirer.module.decode.p25.message.pdu.PDUSequence; -import io.github.dsheirer.module.decode.p25.message.pdu.umbtc.UMBTCMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.umbtc.UMBTCMessage; import io.github.dsheirer.module.decode.p25.reference.Digit; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tdu/TDULinkControlMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tdu/TDULinkControlMessage.java similarity index 92% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tdu/TDULinkControlMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tdu/TDULinkControlMessage.java index 3361da522..b19bd41ca 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tdu/TDULinkControlMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tdu/TDULinkControlMessage.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -17,7 +17,7 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tdu; +package io.github.dsheirer.module.decode.p25.phase1.message.tdu; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.bits.CorrectedBinaryMessage; @@ -25,11 +25,11 @@ import io.github.dsheirer.edac.Golay24; import io.github.dsheirer.edac.ReedSolomon_63_47_17; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWord; -import io.github.dsheirer.module.decode.p25.message.lc.LinkControlWordFactory; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.P25Message; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWord; +import io.github.dsheirer.module.decode.p25.phase1.message.lc.LinkControlWordFactory; import java.util.Collections; import java.util.List; @@ -69,9 +69,9 @@ public TDULinkControlMessage(CorrectedBinaryMessage message, int nac, long times } @Override - public DataUnitID getDUID() + public P25P1DataUnitID getDUID() { - return DataUnitID.TERMINATOR_DATA_UNIT_LINK_CONTROL; + return P25P1DataUnitID.TERMINATOR_DATA_UNIT_LINK_CONTROL; } public LinkControlWord getLinkControlWord() diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tdu/TDUMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tdu/TDUMessage.java new file mode 100644 index 000000000..797abdbb2 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tdu/TDUMessage.java @@ -0,0 +1,56 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tdu; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +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 java.util.Collections; +import java.util.List; + +public class TDUMessage extends P25Message +{ + public TDUMessage(CorrectedBinaryMessage message, int nac, long timestamp) + { + super(message, nac, timestamp); + } + + @Override + public P25P1DataUnitID getDUID() + { + return P25P1DataUnitID.TERMINATOR_DATA_UNIT; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getMessageStub()); + return sb.toString(); + } + + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/ISPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/ISPMessage.java new file mode 100644 index 000000000..a8d029c37 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/ISPMessage.java @@ -0,0 +1,50 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.reference.Direction; + +/** + * P25 Inbound (ISP) TSBK Message + */ +public abstract class ISPMessage extends TSBKMessage +{ + /** + * Constructs an inbound (ISP) TSBK from the binary message sequence. + * + * @param dataUnitID TSBK1/2/3 + * @param message binary sequence + * @param nac decoded from the NID + * @param timestamp for the message + */ + public ISPMessage(P25P1DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestamp) + { + super(dataUnitID, message, nac, timestamp); + } + + @Override + public Direction getDirection() + { + return Direction.INBOUND; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/OSPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/OSPMessage.java new file mode 100644 index 000000000..afdb0b3c6 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/OSPMessage.java @@ -0,0 +1,50 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.reference.Direction; + +/** + * P25 Outbound (OSP) TSBK Message + */ +public abstract class OSPMessage extends TSBKMessage +{ + /** + * Constructs an outbound (OSP) TSBK from the binary message sequence. + * + * @param dataUnitID TSBK1/2/3 + * @param message binary sequence + * @param nac decoded from the NID + * @param timestamp for the message + */ + public OSPMessage(P25P1DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestamp) + { + super(dataUnitID, message, nac, timestamp); + } + + @Override + public Direction getDirection() + { + return Direction.OUTBOUND; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/Opcode.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/Opcode.java similarity index 88% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/Opcode.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/Opcode.java index 8135cb2d0..3bd6f21a7 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/Opcode.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/Opcode.java @@ -1,24 +1,26 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk; import io.github.dsheirer.module.decode.p25.reference.Direction; import io.github.dsheirer.module.decode.p25.reference.Vendor; @@ -176,6 +178,13 @@ public enum Opcode MOTOROLA_OSP_CONTROL_CHANNEL_PLANNED_SHUTDOWN(14, "CCH PLND SHUTDWN", "CONTROL CHANNEL PLANNED SHUTDOWN"), MOTOROLA_OSP_UNKNOWN(-1, "MOTOROLA OSP UNKNOWN OPCODE", "MOTOROLA OSP UNKNOWN OPCODE"), + //Vendor: motorola, Inbound Service Packet (ISP) + HARRIS_ISP_UNKNOWN(-1, "HARRIS ISP UNKNOWN OPCODE", "HARRIS ISP UNKNOWN OPCODE"), + + //Vendor: harris, Outbound Service Packet (OSP) + HARRIS_OSP_TDMA_SYNC(48, "HARRIS TDMA SYNC", "HARRIS TDMA SYNC BROADCAST"), + HARRIS_OSP_UNKNOWN(-1, "HARRIS OSP UNKNOWN OPCODE", "HARRIS OSP UNKNOWN OPCODE"), + //Vendor: unknown, Inbound Service Packet (ISP) UNKNOWN_VENDOR_ISP(-1, "UNKNOWN VENDOR/OPCODE ISP", "UNKNOWN VENDOR ISP OPCODE"), @@ -190,6 +199,8 @@ public enum Opcode OSP_PROTECTION_PARAMETER_UPDATE); public static final EnumSet STANDARD_INBOUND_OPCODES = EnumSet.range(ISP_GROUP_VOICE_SERVICE_REQUEST, ISP_RESERVED_3F); + public static final EnumSet DATA_CHANNEL_GRANT_OPCODES = EnumSet.of(OSP_SNDCP_DATA_CHANNEL_GRANT, + OSP_INDIVIDUAL_DATA_CHANNEL_GRANT, OSP_GROUP_DATA_CHANNEL_GRANT); Opcode(int code, String label, String description) { @@ -222,6 +233,14 @@ public int getCode() return mCode; } + /** + * Indicates if this opcode is an SNDCP data channel grant opcode + */ + public boolean isDataChannelGrant() + { + return DATA_CHANNEL_GRANT_OPCODES.contains(this); + } + @Override public String toString() { @@ -274,6 +293,21 @@ public static Opcode fromValue(int value, Direction direction, Vendor vendor) return ISP_UNKNOWN; } + case HARRIS: + if(direction == Direction.INBOUND) + { + return HARRIS_ISP_UNKNOWN; + } + else + { + switch(value) + { + case 48: + return HARRIS_OSP_TDMA_SYNC; + default: + return HARRIS_OSP_UNKNOWN; + } + } case MOTOROLA: if(direction == Direction.INBOUND) { diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/TSBKMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/TSBKMessage.java similarity index 91% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/TSBKMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/TSBKMessage.java index 51de8b99f..69c34bebe 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/TSBKMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/TSBKMessage.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk; import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.edac.CRCP25; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.P25Utils; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +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.reference.Direction; import io.github.dsheirer.module.decode.p25.reference.Vendor; @@ -42,7 +42,7 @@ public abstract class TSBKMessage extends P25Message 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 DataUnitID mDataUnitID; + private P25P1DataUnitID mDataUnitID; /** * Constructs a TSBK from the binary message sequence. @@ -52,7 +52,7 @@ public abstract class TSBKMessage extends P25Message * @param nac decoded from the NID * @param timestamp for the message */ - public TSBKMessage(DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestamp) + public TSBKMessage(P25P1DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestamp) { super(message, nac, timestamp); mDataUnitID = dataUnitID; @@ -67,7 +67,7 @@ public TSBKMessage(DataUnitID dataUnitID, CorrectedBinaryMessage message, int na } @Override - public DataUnitID getDUID() + public P25P1DataUnitID getDUID() { return mDataUnitID; } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/TSBKMessageFactory.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/TSBKMessageFactory.java similarity index 53% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/TSBKMessageFactory.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/TSBKMessageFactory.java index c23d8f9c7..6a2015cba 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/TSBKMessageFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/TSBKMessageFactory.java @@ -1,115 +1,121 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.edac.trellis.ViterbiDecoder_1_2_P25; -import io.github.dsheirer.module.decode.p25.P25Interleave; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.isp.UnknownMotorolaISPMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.ChannelCWID; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.ChannelLoading; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.MotorolaDenyResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PatchGroupAdd; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PatchGroupDelete; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.PlannedChannelShutdown; -import io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp.UnknownMotorolaOSPMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.AuthenticationQuery; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.CallAlertRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.CancelServiceRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.EmergencyAlarmRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.ExtendedFunctionResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.FrequencyBandUpdateRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.GroupAffiliationQueryResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.GroupAffiliationRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.GroupVoiceServiceRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.IndividualDataServiceRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.LocationRegistrationRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.MessageUpdateRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.ProtectionParameterRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.RadioUnitMonitorRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.RoamingAddressRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.RoamingAddressResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.SNDCPDataChannelRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.SNDCPDataPageResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.SNDCPReconnectRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.StatusQueryRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.StatusQueryResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.StatusUpdateRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.TelephoneInterconnectAnswerResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.TelephoneInterconnectPstnRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitAcknowledgeResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitDeRegistrationRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitRegistrationRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitToUnitVoiceServiceAnswerResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnitToUnitVoiceServiceRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp.UnknownISPMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.AcknowledgeResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.AdjacentStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.AuthenticationCommand; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.CallAlert; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.DenyResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.ExtendedFunctionCommand; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.FrequencyBandUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.FrequencyBandUpdateTDMA; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.FrequencyBandUpdateVUHF; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupAffiliationQuery; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupAffiliationResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupDataChannelAnnouncement; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupDataChannelAnnouncementExplicit; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupDataChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupVoiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupVoiceChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.GroupVoiceChannelGrantUpdateExplicit; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.IndividualDataChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.LocationRegistrationResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.MessageUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.NetworkStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.ProtectionParameterUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.QueuedResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.RFSSStatusBroadcast; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.RadioUnitMonitorCommand; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.RoamingAddressCommand; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SNDCPDataChannelAnnouncementExplicit; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SNDCPDataChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SNDCPDataPageRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SecondaryControlChannelBroadcast; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.StatusQuery; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.StatusUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SyncBroadcast; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.SystemServiceBroadcast; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.TelephoneInterconnectAnswerRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.TelephoneInterconnectVoiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.TelephoneInterconnectVoiceChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnitDeRegistrationAcknowledge; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnitRegistrationCommand; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnitRegistrationResponse; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnitToUnitAnswerRequest; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrant; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrantUpdate; -import io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp.UnknownOSPMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.unknown.isp.UnknownVendorISPMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.unknown.osp.UnknownVendorOSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1Interleave; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.harris.isp.UnknownHarrisISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.harris.osp.HarrisTDMASyncBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.harris.osp.UnknownHarrisOSPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.isp.UnknownMotorolaISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.ChannelLoading; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.MotorolaBaseStationId; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.MotorolaDenyResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.PatchGroupAdd; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.PatchGroupDelete; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.PatchGroupVoiceChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.PlannedChannelShutdown; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp.UnknownMotorolaOSPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.AuthenticationQuery; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.CallAlertRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.CancelServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.EmergencyAlarmRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.ExtendedFunctionResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.FrequencyBandUpdateRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.GroupAffiliationQueryResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.GroupAffiliationRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.GroupVoiceServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.IndividualDataServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.LocationRegistrationRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.MessageUpdateRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.ProtectionParameterRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.RadioUnitMonitorRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.RoamingAddressRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.RoamingAddressResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.SNDCPDataChannelRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.SNDCPDataPageResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.SNDCPReconnectRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.StatusQueryRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.StatusQueryResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.StatusUpdateRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.TelephoneInterconnectAnswerResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.TelephoneInterconnectPstnRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitAcknowledgeResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitDeRegistrationRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitRegistrationRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitToUnitVoiceServiceAnswerResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnitToUnitVoiceServiceRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp.UnknownISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.AcknowledgeResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.AdjacentStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.AuthenticationCommand; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.CallAlert; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.DenyResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.ExtendedFunctionCommand; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.FrequencyBandUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.FrequencyBandUpdateTDMA; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.FrequencyBandUpdateVUHF; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupAffiliationQuery; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupAffiliationResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupDataChannelAnnouncement; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupDataChannelAnnouncementExplicit; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupDataChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupVoiceChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupVoiceChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.GroupVoiceChannelGrantUpdateExplicit; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.IndividualDataChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.LocationRegistrationResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.MessageUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.NetworkStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.ProtectionParameterUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.QueuedResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.RFSSStatusBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.RadioUnitMonitorCommand; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.RoamingAddressCommand; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SNDCPDataChannelAnnouncementExplicit; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SNDCPDataChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SNDCPDataPageRequest; +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.StatusQuery; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.StatusUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SyncBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.SystemServiceBroadcast; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.TelephoneInterconnectAnswerRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.TelephoneInterconnectVoiceChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.TelephoneInterconnectVoiceChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitDeRegistrationAcknowledge; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitRegistrationCommand; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitRegistrationResponse; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitToUnitAnswerRequest; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrant; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnknownOSPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.unknown.isp.UnknownVendorISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.unknown.osp.UnknownVendorOSPMessage; import io.github.dsheirer.module.decode.p25.reference.Direction; import io.github.dsheirer.module.decode.p25.reference.Vendor; @@ -120,11 +126,11 @@ public class TSBKMessageFactory { private static final ViterbiDecoder_1_2_P25 VITERBI_HALF_RATE_DECODER = new ViterbiDecoder_1_2_P25(); - public static TSBKMessage create(Direction direction, DataUnitID dataUnitID, + public static TSBKMessage create(Direction direction, P25P1DataUnitID dataUnitID, CorrectedBinaryMessage correctedBinaryMessage, int nac, long timestamp) { //Get deinterleaved header chunk - CorrectedBinaryMessage deinterleaved = P25Interleave.deinterleaveChunk(P25Interleave.DATA_DEINTERLEAVE, correctedBinaryMessage); + CorrectedBinaryMessage deinterleaved = P25P1Interleave.deinterleaveChunk(P25P1Interleave.DATA_DEINTERLEAVE, correctedBinaryMessage); //Decode 1/2 rate trellis encoded PDU header CorrectedBinaryMessage message = VITERBI_HALF_RATE_DECODER.decode(deinterleaved); @@ -251,6 +257,8 @@ public static TSBKMessage create(Direction direction, DataUnitID dataUnitID, return new RFSSStatusBroadcast(dataUnitID, message, nac, timestamp); case OSP_SECONDARY_CONTROL_CHANNEL_BROADCAST: return new SecondaryControlChannelBroadcast(dataUnitID, message, nac, timestamp); + case OSP_SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT: + return new SecondaryControlChannelBroadcastExplicit(dataUnitID, message, nac, timestamp); case OSP_SNDCP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT: return new SNDCPDataChannelAnnouncementExplicit(dataUnitID, message, nac, timestamp); case OSP_SNDCP_DATA_CHANNEL_GRANT: @@ -284,17 +292,23 @@ public static TSBKMessage create(Direction direction, DataUnitID dataUnitID, case OSP_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE: return new UnitToUnitVoiceChannelGrantUpdate(dataUnitID, message, nac, timestamp); + case HARRIS_ISP_UNKNOWN: + return new UnknownHarrisISPMessage(dataUnitID, message, nac, timestamp); + case HARRIS_OSP_TDMA_SYNC: + return new HarrisTDMASyncBroadcast(dataUnitID, message, nac, timestamp); + case HARRIS_OSP_UNKNOWN: + return new UnknownHarrisOSPMessage(dataUnitID, message, nac, timestamp); + case MOTOROLA_ISP_UNKNOWN: return new UnknownMotorolaISPMessage(dataUnitID, message, nac, timestamp); - case MOTOROLA_OSP_CONTROL_CHANNEL_ID: - return new ChannelCWID(dataUnitID, message, nac, timestamp); + return new MotorolaBaseStationId(dataUnitID, message, nac, timestamp); case MOTOROLA_OSP_CONTROL_CHANNEL_PLANNED_SHUTDOWN: return new PlannedChannelShutdown(dataUnitID, message, nac, timestamp); case MOTOROLA_OSP_DENY_RESPONSE: return new MotorolaDenyResponse(dataUnitID, message, nac, timestamp); case MOTOROLA_OSP_TRAFFIC_CHANNEL_ID: - return new ChannelCWID(dataUnitID, message, nac, timestamp); + return new MotorolaBaseStationId(dataUnitID, message, nac, timestamp); case MOTOROLA_OSP_PATCH_GROUP_ADD: return new PatchGroupAdd(dataUnitID, message, nac, timestamp); case MOTOROLA_OSP_PATCH_GROUP_DELETE: diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tdu/TDUMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/harris/isp/UnknownHarrisISPMessage.java similarity index 57% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tdu/TDUMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/harris/isp/UnknownHarrisISPMessage.java index a0274c349..b58e41bc2 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tdu/TDUMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/harris/isp/UnknownHarrisISPMessage.java @@ -1,50 +1,52 @@ /******************************************************************************* * sdr-trunk - * Copyright (C) 2014-2018 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. + * 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 * ******************************************************************************/ -package io.github.dsheirer.module.decode.p25.message.tdu; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.harris.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.Collections; import java.util.List; -public class TDUMessage extends P25Message +/** + * Unknown/Unrecognized opcode message. + */ +public class UnknownHarrisISPMessage extends OSPMessage { - public TDUMessage(CorrectedBinaryMessage message, int nac, long timestamp) + /** + * Constructs a TSBK from the binary message sequence. + */ + public UnknownHarrisISPMessage(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { - super(message, nac, timestamp); + super(dataUnitId, message, nac, timestamp); } - @Override - public DataUnitID getDUID() - { - return DataUnitID.TERMINATOR_DATA_UNIT; - } - - @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getMessageStub()); + sb.append(" HARRIS **UNRECOGNIZED ISP OPCODE**"); + sb.append(" MSG:").append(getMessage().toHexString()); return sb.toString(); } + @Override public List getIdentifiers() { return Collections.EMPTY_LIST; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/harris/osp/HarrisTDMASyncBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/harris/osp/HarrisTDMASyncBroadcast.java new file mode 100644 index 000000000..68af691b7 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/harris/osp/HarrisTDMASyncBroadcast.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * sdr-trunk + * 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 + * + ******************************************************************************/ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.harris.osp; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; + +import java.util.Collections; +import java.util.List; + +/** + * Harris TDMA Sync Broadcast message. + * + * Note: Standard Opcode 48 is a TDMA Sync message, so this likely has something + * to do with TDMA Phase II + */ +public class HarrisTDMASyncBroadcast extends OSPMessage +{ + /** + * Constructs a TSBK from the binary message sequence. + */ + public HarrisTDMASyncBroadcast(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + { + super(dataUnitId, message, nac, timestamp); + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getMessageStub()); + sb.append(" HARRIS TDMA SYNC BROADCAST"); + sb.append(" MSG:").append(getMessage().toHexString()); + return sb.toString(); + + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/harris/osp/UnknownHarrisOSPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/harris/osp/UnknownHarrisOSPMessage.java new file mode 100644 index 000000000..268f8b7c1 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/harris/osp/UnknownHarrisOSPMessage.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * sdr-trunk + * 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 + * + ******************************************************************************/ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.harris.osp; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; + +import java.util.Collections; +import java.util.List; + +/** + * Unknown/Unrecognized opcode message. + */ +public class UnknownHarrisOSPMessage extends OSPMessage +{ + /** + * Constructs a TSBK from the binary message sequence. + */ + public UnknownHarrisOSPMessage(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + { + super(dataUnitId, message, nac, timestamp); + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getMessageStub()); + sb.append(" HARRIS **UNRECOGNIZED OSP OPCODE**"); + sb.append(" MSG:").append(getMessage().toHexString()); + return sb.toString(); + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/isp/UnknownMotorolaISPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/isp/UnknownMotorolaISPMessage.java similarity index 80% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/isp/UnknownMotorolaISPMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/isp/UnknownMotorolaISPMessage.java index bf30b1abb..8fc1c335c 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/isp/UnknownMotorolaISPMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/isp/UnknownMotorolaISPMessage.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.motorola.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.Collections; import java.util.List; @@ -36,7 +36,7 @@ public class UnknownMotorolaISPMessage extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnknownMotorolaISPMessage(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnknownMotorolaISPMessage(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/ChannelLoading.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/ChannelLoading.java new file mode 100644 index 000000000..0ec026215 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/ChannelLoading.java @@ -0,0 +1,95 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; + +import java.util.Collections; +import java.util.List; + +/** + * Unknown Motorola Opcode that is suspected to be used to indicate Site/Channel loading + * + * Note: I did some analysis of the first 2 octets following the vendor id octet. The second octet value appears to + * only use the 2 MSBs and these seem to be locked to the first octet value, serving as a (redundant) counter to the + * first octet. What's odd is that the sequencing of the first octet skips every 4th value in the sequence, and this + * is supported by the rollover of the second octet counter. + * + * 000 00000000 00 + * 014 00000001 01 + * 028 00000010 10 + * 03C 00000011 11 + * + * 050 00000101 00 (skipped 040 ?) + * 064 00000110 01 + * 078 00000111 10 (lowest observed value?) + * 08C 00001000 11 + * + * 0A0 00001010 00 (skipped 090) + * 0B4 00001011 01 + * 0C8 00001100 10 + * 0DC 00001101 11 + * + * 0F0 00001111 00 (skipped 0E0) + * 104 00010000 01 + * 118 00010001 10 + * 12C 00010010 11 + * + * 140 00010100 00 (skipped 130) + * 154 00010101 01 + * 168 00010110 10 + * 17C 00010111 11 + * + * 190 00011001 00 (skipped 180) + * 1A4 00011010 01 + * 1B8 00011011 10 + * 1CC 00011100 11 + */ +public class ChannelLoading extends OSPMessage +{ + /** + * Constructs a TSBK from the binary message sequence. + */ + public ChannelLoading(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + { + super(dataUnitId, message, nac, timestamp); + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getMessageStub()); + sb.append(" MOTOROLA"); + sb.append(" MSG:").append(getMessage().toHexString()); + return sb.toString(); + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/ChannelCWID.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/MotorolaBaseStationId.java similarity index 68% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/ChannelCWID.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/MotorolaBaseStationId.java index 577d9b33b..fee7f9888 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/ChannelCWID.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/MotorolaBaseStationId.java @@ -1,37 +1,39 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; 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.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class ChannelCWID extends OSPMessage implements IFrequencyBandReceiver +public class MotorolaBaseStationId extends OSPMessage implements IFrequencyBandReceiver { public static final int[] CHARACTER_1 = {16, 17, 18, 19, 20, 21}; public static final int[] CHARACTER_2 = {22, 23, 24, 25, 26, 27}; @@ -47,7 +49,7 @@ public class ChannelCWID extends OSPMessage implements IFrequencyBandReceiver private String mCWID; private IChannelDescriptor mChannel; - public ChannelCWID(DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestamp) + public MotorolaBaseStationId(P25P1DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitID, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/MotorolaDenyResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/MotorolaDenyResponse.java similarity index 90% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/MotorolaDenyResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/MotorolaDenyResponse.java index 1ec4b41e9..0bc9187ad 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/MotorolaDenyResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/MotorolaDenyResponse.java @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; import io.github.dsheirer.module.decode.p25.reference.DenyReason; import io.github.dsheirer.module.decode.p25.reference.Direction; import io.github.dsheirer.module.decode.p25.reference.Vendor; @@ -54,7 +54,7 @@ public class MotorolaDenyResponse extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public MotorolaDenyResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public MotorolaDenyResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PatchGroupAdd.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PatchGroupAdd.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PatchGroupAdd.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PatchGroupAdd.java index 2970b9a96..a56d3bdb5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PatchGroupAdd.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PatchGroupAdd.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -17,7 +17,7 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; @@ -25,8 +25,8 @@ 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.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -45,7 +45,7 @@ public class PatchGroupAdd extends OSPMessage private List mPatchedTalkgroups; private List mIdentifiers; - public PatchGroupAdd(DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timeslot) + public PatchGroupAdd(P25P1DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timeslot) { super(dataUnitID, message, nac, timeslot); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PatchGroupDelete.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PatchGroupDelete.java similarity index 93% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PatchGroupDelete.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PatchGroupDelete.java index 91b811a7c..a9f8ba9f5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PatchGroupDelete.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PatchGroupDelete.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -17,7 +17,7 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; @@ -25,8 +25,8 @@ 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.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -45,7 +45,7 @@ public class PatchGroupDelete extends OSPMessage private List mPatchedTalkgroups; private List mIdentifiers; - public PatchGroupDelete(DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timeslot) + public PatchGroupDelete(P25P1DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timeslot) { super(dataUnitID, message, nac, timeslot); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PatchGroupVoiceChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PatchGroupVoiceChannelGrant.java similarity index 90% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PatchGroupVoiceChannelGrant.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PatchGroupVoiceChannelGrant.java index d914e5ead..b7fe2328d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PatchGroupVoiceChannelGrant.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PatchGroupVoiceChannelGrant.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -17,7 +17,7 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -28,9 +28,9 @@ import io.github.dsheirer.module.decode.p25.identifier.patch.APCO25PatchGroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -51,7 +51,7 @@ public class PatchGroupVoiceChannelGrant extends OSPMessage implements IFrequenc private PatchGroupIdentifier mPatchGroup; private List mIdentifiers; - public PatchGroupVoiceChannelGrant(DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestlot) + public PatchGroupVoiceChannelGrant(P25P1DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestlot) { super(dataUnitID, message, nac, timestlot); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PatchGroupVoiceChannelGrantUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PatchGroupVoiceChannelGrantUpdate.java similarity index 90% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PatchGroupVoiceChannelGrantUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PatchGroupVoiceChannelGrantUpdate.java index 631883dd5..9e30b5f47 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PatchGroupVoiceChannelGrantUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PatchGroupVoiceChannelGrantUpdate.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -17,7 +17,7 @@ * along with this program. If not, see * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -27,9 +27,9 @@ 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.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -49,7 +49,7 @@ public class PatchGroupVoiceChannelGrantUpdate extends OSPMessage implements IFr private APCO25Channel mChannel2; private List mIdentifiers; - public PatchGroupVoiceChannelGrantUpdate(DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestamp) + public PatchGroupVoiceChannelGrantUpdate(P25P1DataUnitID dataUnitID, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitID, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PlannedChannelShutdown.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PlannedChannelShutdown.java similarity index 80% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PlannedChannelShutdown.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PlannedChannelShutdown.java index ee0aea2e1..2ca77f61c 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/PlannedChannelShutdown.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/PlannedChannelShutdown.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.Collections; import java.util.List; @@ -36,7 +36,7 @@ public class PlannedChannelShutdown extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public PlannedChannelShutdown(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public PlannedChannelShutdown(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/UnknownMotorolaOSPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/UnknownMotorolaOSPMessage.java similarity index 80% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/UnknownMotorolaOSPMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/UnknownMotorolaOSPMessage.java index 0933eac10..bb94b8766 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/UnknownMotorolaOSPMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/motorola/osp/UnknownMotorolaOSPMessage.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.motorola.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.Collections; import java.util.List; @@ -36,7 +36,7 @@ public class UnknownMotorolaOSPMessage extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnknownMotorolaOSPMessage(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnknownMotorolaOSPMessage(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/AuthenticationQuery.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/AuthenticationQuery.java similarity index 64% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/AuthenticationQuery.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/AuthenticationQuery.java index e633740e4..fdef202a3 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/AuthenticationQuery.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/AuthenticationQuery.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -28,7 +48,7 @@ public class AuthenticationQuery extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public AuthenticationQuery(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public AuthenticationQuery(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/CallAlertRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/CallAlertRequest.java similarity index 64% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/CallAlertRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/CallAlertRequest.java index d89fb3255..85d08dbc9 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/CallAlertRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/CallAlertRequest.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -28,7 +48,7 @@ public class CallAlertRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public CallAlertRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public CallAlertRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/CancelServiceRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/CancelServiceRequest.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/CancelServiceRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/CancelServiceRequest.java index 1542ce505..12bcb2cf5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/CancelServiceRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/CancelServiceRequest.java @@ -1,12 +1,32 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; import io.github.dsheirer.module.decode.p25.reference.CancelReason; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import io.github.dsheirer.module.decode.p25.reference.Direction; import java.util.ArrayList; @@ -32,7 +52,7 @@ public class CancelServiceRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public CancelServiceRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public CancelServiceRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/EmergencyAlarmRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/EmergencyAlarmRequest.java similarity index 63% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/EmergencyAlarmRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/EmergencyAlarmRequest.java index e61a96d99..1a8dc7aec 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/EmergencyAlarmRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/EmergencyAlarmRequest.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -28,7 +48,7 @@ public class EmergencyAlarmRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public EmergencyAlarmRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public EmergencyAlarmRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/ExtendedFunctionResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/ExtendedFunctionResponse.java similarity index 66% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/ExtendedFunctionResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/ExtendedFunctionResponse.java index 4ec91f85b..c52e1a82a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/ExtendedFunctionResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/ExtendedFunctionResponse.java @@ -1,10 +1,30 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.ExtendedFunction; import java.util.ArrayList; @@ -29,7 +49,7 @@ public class ExtendedFunctionResponse extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public ExtendedFunctionResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public ExtendedFunctionResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/FrequencyBandUpdateRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/FrequencyBandUpdateRequest.java similarity index 65% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/FrequencyBandUpdateRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/FrequencyBandUpdateRequest.java index 4b8cc16e1..3eb9fb2e9 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/FrequencyBandUpdateRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/FrequencyBandUpdateRequest.java @@ -1,10 +1,30 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -28,7 +48,7 @@ public class FrequencyBandUpdateRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public FrequencyBandUpdateRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public FrequencyBandUpdateRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/GroupAffiliationQueryResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/GroupAffiliationQueryResponse.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/GroupAffiliationQueryResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/GroupAffiliationQueryResponse.java index f745139a0..d5a5ecf46 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/GroupAffiliationQueryResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/GroupAffiliationQueryResponse.java @@ -1,12 +1,32 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25AnnouncementTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -31,7 +51,7 @@ public class GroupAffiliationQueryResponse extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public GroupAffiliationQueryResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public GroupAffiliationQueryResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/GroupAffiliationRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/GroupAffiliationRequest.java similarity index 67% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/GroupAffiliationRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/GroupAffiliationRequest.java index 1d04f2b2f..fc652e041 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/GroupAffiliationRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/GroupAffiliationRequest.java @@ -1,12 +1,32 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; 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.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -30,7 +50,7 @@ public class GroupAffiliationRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public GroupAffiliationRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public GroupAffiliationRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/GroupDataServiceRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/GroupDataServiceRequest.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/GroupDataServiceRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/GroupDataServiceRequest.java index a8ccb21c7..456a9501c 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/GroupDataServiceRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/GroupDataServiceRequest.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -30,7 +50,7 @@ public class GroupDataServiceRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public GroupDataServiceRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public GroupDataServiceRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/GroupVoiceServiceRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/GroupVoiceServiceRequest.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/GroupVoiceServiceRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/GroupVoiceServiceRequest.java index a5f57633f..921121aa0 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/GroupVoiceServiceRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/GroupVoiceServiceRequest.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -30,7 +50,7 @@ public class GroupVoiceServiceRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public GroupVoiceServiceRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public GroupVoiceServiceRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/IndividualDataServiceRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/IndividualDataServiceRequest.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/IndividualDataServiceRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/IndividualDataServiceRequest.java index 3217d5417..8ed8e3d1a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/IndividualDataServiceRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/IndividualDataServiceRequest.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -31,7 +51,7 @@ public class IndividualDataServiceRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public IndividualDataServiceRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public IndividualDataServiceRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/LocationRegistrationRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/LocationRegistrationRequest.java similarity index 73% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/LocationRegistrationRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/LocationRegistrationRequest.java index 3dd5821c2..2d973bf69 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/LocationRegistrationRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/LocationRegistrationRequest.java @@ -1,13 +1,33 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.Capability; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import java.util.ArrayList; import java.util.List; @@ -34,7 +54,7 @@ public class LocationRegistrationRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public LocationRegistrationRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public LocationRegistrationRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/MessageUpdateRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/MessageUpdateRequest.java similarity index 65% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/MessageUpdateRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/MessageUpdateRequest.java index 5dbc5a19e..e85dd2e37 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/MessageUpdateRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/MessageUpdateRequest.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -28,7 +48,7 @@ public class MessageUpdateRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public MessageUpdateRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public MessageUpdateRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/ProtectionParameterRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/ProtectionParameterRequest.java similarity index 66% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/ProtectionParameterRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/ProtectionParameterRequest.java index 98fdc1c07..773a7dc96 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/ProtectionParameterRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/ProtectionParameterRequest.java @@ -1,12 +1,32 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; 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.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -30,7 +50,7 @@ public class ProtectionParameterRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public ProtectionParameterRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public ProtectionParameterRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/RadioUnitMonitorCommand.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/RadioUnitMonitorRequest.java similarity index 82% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/RadioUnitMonitorCommand.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/RadioUnitMonitorRequest.java index 3794dcc93..34bcc3ca0 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/RadioUnitMonitorCommand.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/RadioUnitMonitorRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,38 +18,38 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; /** - * Radio unit monitor command + * Radio unit monitor request */ -public class RadioUnitMonitorCommand extends OSPMessage +public class RadioUnitMonitorRequest extends ISPMessage { private static final int[] RESERVED = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}; private static final int[] TX_MULTIPLIER = {30, 31}; - private static final int[] SOURCE_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55}; - private static final int[] TARGET_ADDRESS = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79}; + private static final int[] TARGET_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55}; + private static final int[] SOURCE_ADDRESS = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79}; - private Identifier mSourceAddress; private Identifier mTargetAddress; + private Identifier mSourceAddress; private List mIdentifiers; /** * Constructs a TSBK from the binary message sequence. */ - public RadioUnitMonitorCommand(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public RadioUnitMonitorRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/RoamingAddressRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/RoamingAddressRequest.java similarity index 64% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/RoamingAddressRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/RoamingAddressRequest.java index f7fdd5302..822812f23 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/RoamingAddressRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/RoamingAddressRequest.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -28,7 +48,7 @@ public class RoamingAddressRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public RoamingAddressRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public RoamingAddressRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/RoamingAddressResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/RoamingAddressResponse.java similarity index 70% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/RoamingAddressResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/RoamingAddressResponse.java index 38707b7fd..efe16adc5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/RoamingAddressResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/RoamingAddressResponse.java @@ -1,12 +1,32 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; 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.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -31,7 +51,7 @@ public class RoamingAddressResponse extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public RoamingAddressResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public RoamingAddressResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/SNDCPDataChannelRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/SNDCPDataChannelRequest.java similarity index 89% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/SNDCPDataChannelRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/SNDCPDataChannelRequest.java index 19f854f9c..070658ced 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/SNDCPDataChannelRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/SNDCPDataChannelRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import java.util.ArrayList; import java.util.List; @@ -48,7 +48,7 @@ public class SNDCPDataChannelRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public SNDCPDataChannelRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public SNDCPDataChannelRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/SNDCPDataPageResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/SNDCPDataPageResponse.java similarity index 90% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/SNDCPDataPageResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/SNDCPDataPageResponse.java index 68573e4e8..5bc3d7140 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/SNDCPDataPageResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/SNDCPDataPageResponse.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.AnswerResponse; import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import java.util.ArrayList; import java.util.List; @@ -50,7 +50,7 @@ public class SNDCPDataPageResponse extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public SNDCPDataPageResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public SNDCPDataPageResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/SNDCPReconnectRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/SNDCPReconnectRequest.java similarity index 89% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/SNDCPReconnectRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/SNDCPReconnectRequest.java index 47387bf16..0d814154f 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/SNDCPReconnectRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/SNDCPReconnectRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import java.util.ArrayList; import java.util.List; @@ -49,7 +49,7 @@ public class SNDCPReconnectRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public SNDCPReconnectRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public SNDCPReconnectRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/StatusQueryRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/StatusQueryRequest.java similarity index 64% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/StatusQueryRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/StatusQueryRequest.java index 35c9337dc..0d68e0855 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/StatusQueryRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/StatusQueryRequest.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -28,7 +48,7 @@ public class StatusQueryRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public StatusQueryRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public StatusQueryRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/StatusQueryResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/StatusQueryResponse.java similarity index 91% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/StatusQueryResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/StatusQueryResponse.java index f4d784c00..4e4716986 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/StatusQueryResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/StatusQueryResponse.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; @@ -26,8 +26,8 @@ import io.github.dsheirer.module.decode.p25.identifier.status.APCO25UserStatus; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -53,7 +53,7 @@ public class StatusQueryResponse extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public StatusQueryResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public StatusQueryResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/StatusUpdateRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/StatusUpdateRequest.java similarity index 91% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/StatusUpdateRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/StatusUpdateRequest.java index d7a6e7920..0652fe3d2 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/StatusUpdateRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/StatusUpdateRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; @@ -26,8 +26,8 @@ import io.github.dsheirer.module.decode.p25.identifier.status.APCO25UserStatus; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -53,7 +53,7 @@ public class StatusUpdateRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public StatusUpdateRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public StatusUpdateRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/TelephoneInterconnectAnswerResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/TelephoneInterconnectAnswerResponse.java similarity index 67% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/TelephoneInterconnectAnswerResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/TelephoneInterconnectAnswerResponse.java index d1f66ec81..deaf233bb 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/TelephoneInterconnectAnswerResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/TelephoneInterconnectAnswerResponse.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.AnswerResponse; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -30,7 +50,7 @@ public class TelephoneInterconnectAnswerResponse extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public TelephoneInterconnectAnswerResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public TelephoneInterconnectAnswerResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/TelephoneInterconnectPstnRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/TelephoneInterconnectPstnRequest.java similarity index 70% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/TelephoneInterconnectPstnRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/TelephoneInterconnectPstnRequest.java index a5e91267e..6e04da558 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/TelephoneInterconnectPstnRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/TelephoneInterconnectPstnRequest.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.telephone.APCO25TelephoneNumber; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -32,7 +52,7 @@ public class TelephoneInterconnectPstnRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public TelephoneInterconnectPstnRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public TelephoneInterconnectPstnRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitAcknowledgeResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitAcknowledgeResponse.java similarity index 67% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitAcknowledgeResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitAcknowledgeResponse.java index 130d34eef..ca282f610 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitAcknowledgeResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitAcknowledgeResponse.java @@ -1,12 +1,32 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; import io.github.dsheirer.module.decode.p25.reference.Direction; import io.github.dsheirer.module.decode.p25.reference.Vendor; @@ -32,7 +52,7 @@ public class UnitAcknowledgeResponse extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnitAcknowledgeResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnitAcknowledgeResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitDeRegistrationRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitDeRegistrationRequest.java similarity index 66% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitDeRegistrationRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitDeRegistrationRequest.java index a49bdefae..e21bc4cc4 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitDeRegistrationRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitDeRegistrationRequest.java @@ -1,12 +1,32 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; 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.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.ArrayList; import java.util.List; @@ -30,7 +50,7 @@ public class UnitDeRegistrationRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnitDeRegistrationRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnitDeRegistrationRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitRegistrationRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitRegistrationRequest.java similarity index 71% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitRegistrationRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitRegistrationRequest.java index 0fb085df3..21dd7b782 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitRegistrationRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitRegistrationRequest.java @@ -1,13 +1,33 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; 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.talkgroup.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.Capability; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import java.util.ArrayList; import java.util.List; @@ -33,7 +53,7 @@ public class UnitRegistrationRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnitRegistrationRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnitRegistrationRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitToUnitVoiceServiceAnswerResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitToUnitVoiceServiceAnswerResponse.java similarity index 71% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitToUnitVoiceServiceAnswerResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitToUnitVoiceServiceAnswerResponse.java index 5bdfeb160..86d44969e 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitToUnitVoiceServiceAnswerResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitToUnitVoiceServiceAnswerResponse.java @@ -1,12 +1,32 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.AnswerResponse; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -32,7 +52,7 @@ public class UnitToUnitVoiceServiceAnswerResponse extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnitToUnitVoiceServiceAnswerResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnitToUnitVoiceServiceAnswerResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitToUnitVoiceServiceRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitToUnitVoiceServiceRequest.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitToUnitVoiceServiceRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitToUnitVoiceServiceRequest.java index 192f1b43c..d14dfd8c5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/UnitToUnitVoiceServiceRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnitToUnitVoiceServiceRequest.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -31,7 +51,7 @@ public class UnitToUnitVoiceServiceRequest extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnitToUnitVoiceServiceRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnitToUnitVoiceServiceRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/ChannelLoading.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnknownISPMessage.java similarity index 73% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/ChannelLoading.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnknownISPMessage.java index 3c7a0cc85..4d63454f7 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/motorola/osp/ChannelLoading.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/isp/UnknownISPMessage.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,25 +18,25 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.motorola.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import java.util.Collections; import java.util.List; /** - * Channel loading + * Unknown/Unrecognized opcode message. */ -public class ChannelLoading extends OSPMessage +public class UnknownISPMessage extends ISPMessage { /** * Constructs a TSBK from the binary message sequence. */ - public ChannelLoading(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnknownISPMessage(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } @@ -45,7 +45,7 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getMessageStub()); - sb.append(" MOTOROLA"); + sb.append(" **UNRECOGNIZED ISP OPCODE**"); sb.append(" MSG:").append(getMessage().toHexString()); return sb.toString(); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/AcknowledgeResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/AcknowledgeResponse.java similarity index 79% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/AcknowledgeResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/AcknowledgeResponse.java index b8d992c43..0b9880350 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/AcknowledgeResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/AcknowledgeResponse.java @@ -1,4 +1,24 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; @@ -6,9 +26,9 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25Wacn; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; import io.github.dsheirer.module.decode.p25.reference.Direction; import io.github.dsheirer.module.decode.p25.reference.Vendor; @@ -39,7 +59,7 @@ public class AcknowledgeResponse extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public AcknowledgeResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public AcknowledgeResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/AdjacentStatusBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/AdjacentStatusBroadcast.java similarity index 76% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/AdjacentStatusBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/AdjacentStatusBroadcast.java index 6d574a04c..d1e6e504d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/AdjacentStatusBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/AdjacentStatusBroadcast.java @@ -1,4 +1,26 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -8,10 +30,10 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; import io.github.dsheirer.module.decode.p25.identifier.APCO25System; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; -import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; import java.util.ArrayList; import java.util.List; @@ -38,14 +60,14 @@ public class AdjacentStatusBroadcast extends OSPMessage implements IFrequencyBan private Identifier mSite; private Identifier mRfss; private IChannelDescriptor mChannel; - private VoiceServiceOptions mVoiceServiceOptions; + private SystemServiceClass mSystemServiceClass; private List mIdentifiers; private List mSiteFlags; /** * Constructs a TSBK from the binary message sequence. */ - public AdjacentStatusBroadcast(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public AdjacentStatusBroadcast(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } @@ -54,12 +76,12 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getMessageStub()); - sb.append(" LRA:").append(getLocationRegistrationArea()); sb.append(" SYSTEM:").append(getSystem()); sb.append(" RFSS:").append(getRfss()); sb.append(" SITE:").append(getSite()); + sb.append(" LRA:").append(getLocationRegistrationArea()); sb.append(" FLAGS ").append(getSiteFlags()); - sb.append(" SERVICES ").append(getVoiceServiceOptions()); + sb.append(" SERVICES ").append(getSystemServiceClass()); return sb.toString(); } @@ -175,14 +197,14 @@ public IChannelDescriptor getChannel() return mChannel; } - public VoiceServiceOptions getVoiceServiceOptions() + public SystemServiceClass getSystemServiceClass() { - if(mVoiceServiceOptions == null) + if(mSystemServiceClass == null) { - mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SYSTEM_SERVICE_CLASS)); + mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SYSTEM_SERVICE_CLASS)); } - return mVoiceServiceOptions; + return mSystemServiceClass; } @Override diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/AuthenticationCommand.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/AuthenticationCommand.java similarity index 65% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/AuthenticationCommand.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/AuthenticationCommand.java index 7a20cd41b..886b5dee3 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/AuthenticationCommand.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/AuthenticationCommand.java @@ -1,12 +1,32 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; 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.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -30,7 +50,7 @@ public class AuthenticationCommand extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public AuthenticationCommand(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public AuthenticationCommand(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/CallAlert.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/CallAlert.java similarity index 63% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/CallAlert.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/CallAlert.java index 88dbfc58b..dcfb19daa 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/CallAlert.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/CallAlert.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -28,7 +48,7 @@ public class CallAlert extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public CallAlert(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public CallAlert(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/DenyResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/DenyResponse.java similarity index 70% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/DenyResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/DenyResponse.java index c7655b1bd..7a8bffa13 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/DenyResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/DenyResponse.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; import io.github.dsheirer.module.decode.p25.reference.DenyReason; import io.github.dsheirer.module.decode.p25.reference.Direction; import io.github.dsheirer.module.decode.p25.reference.Vendor; @@ -34,7 +54,7 @@ public class DenyResponse extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public DenyResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public DenyResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/ExtendedFunctionCommand.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/ExtendedFunctionCommand.java similarity index 66% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/ExtendedFunctionCommand.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/ExtendedFunctionCommand.java index 53a408a3c..03f3f14ad 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/ExtendedFunctionCommand.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/ExtendedFunctionCommand.java @@ -1,10 +1,30 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.ExtendedFunction; import java.util.ArrayList; @@ -29,7 +49,7 @@ public class ExtendedFunctionCommand extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public ExtendedFunctionCommand(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public ExtendedFunctionCommand(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/FrequencyBandUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/FrequencyBandUpdate.java similarity index 68% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/FrequencyBandUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/FrequencyBandUpdate.java index 79944b75b..5e083f921 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/FrequencyBandUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/FrequencyBandUpdate.java @@ -1,30 +1,32 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.Collections; import java.util.List; @@ -45,7 +47,7 @@ public class FrequencyBandUpdate extends OSPMessage implements IFrequencyBand /** * Constructs a TSBK from the binary message sequence. */ - public FrequencyBandUpdate(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public FrequencyBandUpdate(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } @@ -89,7 +91,7 @@ public int getBandwidth() @Override public long getTransmitOffset() { - long offset = getMessage().getLong(TRANSMIT_OFFSET) * 250000l; + long offset = getMessage().getLong(TRANSMIT_OFFSET) * getChannelSpacing(); if(!getMessage().get(TRANSMIT_OFFSET_SIGN)) { diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/FrequencyBandUpdateTDMA.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/FrequencyBandUpdateTDMA.java similarity index 68% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/FrequencyBandUpdateTDMA.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/FrequencyBandUpdateTDMA.java index 2b9ab429f..01cc6df25 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/FrequencyBandUpdateTDMA.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/FrequencyBandUpdateTDMA.java @@ -1,31 +1,33 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.ChannelType; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import java.util.Collections; import java.util.List; @@ -48,7 +50,7 @@ public class FrequencyBandUpdateTDMA extends OSPMessage implements IFrequencyBan /** * Constructs a TSBK from the binary message sequence. */ - public FrequencyBandUpdateTDMA(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public FrequencyBandUpdateTDMA(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } @@ -102,7 +104,7 @@ public int getBandwidth() @Override public long getTransmitOffset() { - long offset = getMessage().getLong(TRANSMIT_OFFSET) * 250000l; + long offset = getMessage().getLong(TRANSMIT_OFFSET) * getChannelType().getBandwidth(); if(!getMessage().get(TRANSMIT_OFFSET_SIGN)) { @@ -123,7 +125,7 @@ public boolean hasTransmitOffset() @Override public long getDownlinkFrequency(int channelNumber) { - return getBaseFrequency() + (getChannelSpacing() * channelNumber); + return getBaseFrequency() + (getChannelSpacing() * (int)(Math.floor(channelNumber / getTimeslotCount()))); } @Override diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/FrequencyBandUpdateVUHF.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/FrequencyBandUpdateVUHF.java similarity index 89% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/FrequencyBandUpdateVUHF.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/FrequencyBandUpdateVUHF.java index 380c79f88..d2f45bc54 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/FrequencyBandUpdateVUHF.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/FrequencyBandUpdateVUHF.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,13 +18,13 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBand; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.Collections; import java.util.List; @@ -45,7 +45,7 @@ public class FrequencyBandUpdateVUHF extends OSPMessage implements IFrequencyBan /** * Constructs a TSBK from the binary message sequence. */ - public FrequencyBandUpdateVUHF(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public FrequencyBandUpdateVUHF(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupAffiliationQuery.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupAffiliationQuery.java similarity index 64% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupAffiliationQuery.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupAffiliationQuery.java index 24e1d837e..5bb25ff75 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupAffiliationQuery.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupAffiliationQuery.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -28,7 +48,7 @@ public class GroupAffiliationQuery extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public GroupAffiliationQuery(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public GroupAffiliationQuery(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupAffiliationResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupAffiliationResponse.java similarity index 74% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupAffiliationResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupAffiliationResponse.java index ca7567035..401e07978 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupAffiliationResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupAffiliationResponse.java @@ -1,12 +1,32 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25AnnouncementTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25AnyTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.Response; import java.util.ArrayList; @@ -35,7 +55,7 @@ public class GroupAffiliationResponse extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public GroupAffiliationResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public GroupAffiliationResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupDataChannelAnnouncement.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupDataChannelAnnouncement.java similarity index 72% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupDataChannelAnnouncement.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupDataChannelAnnouncement.java index 19336ec34..5b216cc7a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupDataChannelAnnouncement.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupDataChannelAnnouncement.java @@ -1,13 +1,33 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; 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.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -33,7 +53,7 @@ public class GroupDataChannelAnnouncement extends OSPMessage implements IFrequen /** * Constructs a TSBK from the binary message sequence. */ - public GroupDataChannelAnnouncement(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public GroupDataChannelAnnouncement(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupDataChannelAnnouncementExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupDataChannelAnnouncementExplicit.java similarity index 67% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupDataChannelAnnouncementExplicit.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupDataChannelAnnouncementExplicit.java index 6e98638c9..729afcb63 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupDataChannelAnnouncementExplicit.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupDataChannelAnnouncementExplicit.java @@ -1,13 +1,33 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -32,7 +52,7 @@ public class GroupDataChannelAnnouncementExplicit extends OSPMessage implements /** * Constructs a TSBK from the binary message sequence. */ - public GroupDataChannelAnnouncementExplicit(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public GroupDataChannelAnnouncementExplicit(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupDataChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupDataChannelGrant.java similarity index 90% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupDataChannelGrant.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupDataChannelGrant.java index cb3c00472..f6dd8a179 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupDataChannelGrant.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupDataChannelGrant.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -26,10 +26,10 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import java.util.ArrayList; import java.util.List; @@ -55,7 +55,7 @@ public class GroupDataChannelGrant extends OSPMessage implements IFrequencyBandR /** * Constructs a TSBK from the binary message sequence. */ - public GroupDataChannelGrant(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public GroupDataChannelGrant(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupVoiceChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupVoiceChannelGrant.java similarity index 72% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupVoiceChannelGrant.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupVoiceChannelGrant.java index 094f10ac7..eaaf72aca 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupVoiceChannelGrant.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupVoiceChannelGrant.java @@ -1,4 +1,24 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -6,9 +26,9 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -35,7 +55,7 @@ public class GroupVoiceChannelGrant extends OSPMessage implements IFrequencyBand /** * Constructs a TSBK from the binary message sequence. */ - public GroupVoiceChannelGrant(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public GroupVoiceChannelGrant(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupVoiceChannelGrantUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupVoiceChannelGrantUpdate.java similarity index 73% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupVoiceChannelGrantUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupVoiceChannelGrantUpdate.java index e27a38146..1f95042bd 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupVoiceChannelGrantUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupVoiceChannelGrantUpdate.java @@ -1,13 +1,33 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; 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.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -33,7 +53,7 @@ public class GroupVoiceChannelGrantUpdate extends OSPMessage implements IFrequen /** * Constructs a TSBK from the binary message sequence. */ - public GroupVoiceChannelGrantUpdate(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public GroupVoiceChannelGrantUpdate(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupVoiceChannelGrantUpdateExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupVoiceChannelGrantUpdateExplicit.java similarity index 71% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupVoiceChannelGrantUpdateExplicit.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupVoiceChannelGrantUpdateExplicit.java index f0546f574..18b51b936 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/GroupVoiceChannelGrantUpdateExplicit.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/GroupVoiceChannelGrantUpdateExplicit.java @@ -1,13 +1,33 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -34,7 +54,7 @@ public class GroupVoiceChannelGrantUpdateExplicit extends OSPMessage implements /** * Constructs a TSBK from the binary message sequence. */ - public GroupVoiceChannelGrantUpdateExplicit(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public GroupVoiceChannelGrantUpdateExplicit(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/IndividualDataChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/IndividualDataChannelGrant.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/IndividualDataChannelGrant.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/IndividualDataChannelGrant.java index 8b8770dc3..bba33a6e6 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/IndividualDataChannelGrant.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/IndividualDataChannelGrant.java @@ -1,4 +1,24 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -6,9 +26,9 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -33,7 +53,7 @@ public class IndividualDataChannelGrant extends OSPMessage implements IFrequency /** * Constructs a TSBK from the binary message sequence. */ - public IndividualDataChannelGrant(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public IndividualDataChannelGrant(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/LocationRegistrationResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/LocationRegistrationResponse.java similarity index 91% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/LocationRegistrationResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/LocationRegistrationResponse.java index 7d97ff77d..414c58ce1 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/LocationRegistrationResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/LocationRegistrationResponse.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; @@ -26,8 +26,8 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25AnyTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.Response; import java.util.ArrayList; @@ -56,7 +56,7 @@ public class LocationRegistrationResponse extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public LocationRegistrationResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public LocationRegistrationResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/MessageUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/MessageUpdate.java similarity index 90% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/MessageUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/MessageUpdate.java index 40939e7ca..dedc3a7d7 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/MessageUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/MessageUpdate.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.message.APCO25ShortDataMessage; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -50,7 +50,7 @@ public class MessageUpdate extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public MessageUpdate(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public MessageUpdate(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/NetworkStatusBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/NetworkStatusBroadcast.java similarity index 59% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/NetworkStatusBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/NetworkStatusBroadcast.java index d351bccc0..3d349bc8c 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/NetworkStatusBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/NetworkStatusBroadcast.java @@ -1,24 +1,26 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -27,10 +29,11 @@ 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.channel.APCO25Channel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; -import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; import java.util.ArrayList; import java.util.List; @@ -51,14 +54,15 @@ public class NetworkStatusBroadcast extends OSPMessage implements IFrequencyBand private Identifier mWacn; private Identifier mSystem; private IChannelDescriptor mChannel; - private VoiceServiceOptions mVoiceServiceOptions; + private SystemServiceClass mSystemServiceClass; private List mIdentifiers; private List mSiteFlags; + private ScrambleParameters mScrambleParameters; /** * Constructs a TSBK from the binary message sequence. */ - public NetworkStatusBroadcast(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public NetworkStatusBroadcast(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } @@ -67,13 +71,27 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getMessageStub()); - sb.append(" LRA:").append(getLocationRegistrationArea()); sb.append(" WACN:").append(getWacn()); sb.append(" SYSTEM:").append(getSystem()); - sb.append(" SERVICE OPTIONS:").append(getVoiceServiceOptions()); + sb.append(" LRA:").append(getLocationRegistrationArea()); + sb.append(" SERVICES:").append(getSystemServiceClass().getServices()); return sb.toString(); } + /** + * P25 Phase II scramble (randomizer) parameters. + */ + public ScrambleParameters getScrambleParameters() + { + if(mScrambleParameters == null) + { + mScrambleParameters = new ScrambleParameters((int)getWacn().getValue(), (int)getSystem().getValue(), + (int)getNAC().getValue()); + } + + return mScrambleParameters; + } + public Identifier getLocationRegistrationArea() { if(mLocationRegistrationArea == null) @@ -114,14 +132,14 @@ public IChannelDescriptor getChannel() return mChannel; } - public VoiceServiceOptions getVoiceServiceOptions() + public SystemServiceClass getSystemServiceClass() { - if(mVoiceServiceOptions == null) + if(mSystemServiceClass == null) { - mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SYSTEM_SERVICE_CLASS)); + mSystemServiceClass = SystemServiceClass.create(getMessage().getInt(SYSTEM_SERVICE_CLASS)); } - return mVoiceServiceOptions; + return mSystemServiceClass; } @Override diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/ProtectionParameterUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/ProtectionParameterUpdate.java similarity index 61% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/ProtectionParameterUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/ProtectionParameterUpdate.java index 83cf9bc31..737b39363 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/ProtectionParameterUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/ProtectionParameterUpdate.java @@ -1,31 +1,34 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; 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.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -48,7 +51,7 @@ public class ProtectionParameterUpdate extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public ProtectionParameterUpdate(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public ProtectionParameterUpdate(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } @@ -68,7 +71,7 @@ public Identifier getEncryptionKey() { int algorithm = getMessage().getInt(ALGORITHM_ID); int key = getMessage().getInt(KEY_ID); - mEncryptionKey = APCO25EncryptionKey.create(algorithm, key); + mEncryptionKey = EncryptionKeyIdentifier.create(APCO25EncryptionKey.create(algorithm, key)); } return mEncryptionKey; diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/QueuedResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/QueuedResponse.java similarity index 90% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/QueuedResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/QueuedResponse.java index c313896d1..d450dca36 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/QueuedResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/QueuedResponse.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.Opcode; import io.github.dsheirer.module.decode.p25.reference.Direction; import io.github.dsheirer.module.decode.p25.reference.QueuedResponseReason; import io.github.dsheirer.module.decode.p25.reference.Vendor; @@ -54,7 +54,7 @@ public class QueuedResponse extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public QueuedResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public QueuedResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/RFSSStatusBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/RFSSStatusBroadcast.java similarity index 70% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/RFSSStatusBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/RFSSStatusBroadcast.java index de3ab6349..5ea9a8119 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/RFSSStatusBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/RFSSStatusBroadcast.java @@ -1,24 +1,26 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -28,10 +30,10 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; import io.github.dsheirer.module.decode.p25.identifier.APCO25System; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; -import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; import java.util.ArrayList; import java.util.List; @@ -55,13 +57,13 @@ public class RFSSStatusBroadcast extends OSPMessage implements IFrequencyBandRec private Identifier mSite; private Identifier mRfss; private IChannelDescriptor mChannel; - private VoiceServiceOptions mVoiceServiceOptions; + private SystemServiceClass mSystemServiceClass; private List mIdentifiers; /** * Constructs a TSBK from the binary message sequence. */ - public RFSSStatusBroadcast(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public RFSSStatusBroadcast(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } @@ -70,15 +72,15 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getMessageStub()); - sb.append(" LRA:").append(getLocationRegistrationArea()); sb.append(" SYSTEM:").append(getSystem()); sb.append(" RFSS:").append(getRfss()); sb.append(" SITE:").append(getSite()); + sb.append(" LRA:").append(getLocationRegistrationArea()); if(isActiveNetworkConnectionToRfssControllerSite()) { sb.append(" ACTIVE NETWORK CONNECTION"); } - sb.append(" SERVICE OPTIONS:").append(getVoiceServiceOptions()); + sb.append(" SERVICE OPTIONS:").append(getSystemServiceClass()); return sb.toString(); } @@ -140,14 +142,14 @@ public IChannelDescriptor getChannel() return mChannel; } - public VoiceServiceOptions getVoiceServiceOptions() + public SystemServiceClass getSystemServiceClass() { - if(mVoiceServiceOptions == null) + if(mSystemServiceClass == null) { - mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SYSTEM_SERVICE_CLASS)); + mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SYSTEM_SERVICE_CLASS)); } - return mVoiceServiceOptions; + return mSystemServiceClass; } @Override diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/RadioUnitMonitorRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/RadioUnitMonitorCommand.java similarity index 56% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/RadioUnitMonitorRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/RadioUnitMonitorCommand.java index 797d63977..949d0b953 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/isp/RadioUnitMonitorRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/RadioUnitMonitorCommand.java @@ -1,35 +1,57 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.isp; +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; /** - * Radio unit monitor request + * Radio unit monitor command */ -public class RadioUnitMonitorRequest extends ISPMessage +public class RadioUnitMonitorCommand extends OSPMessage { private static final int[] RESERVED = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}; private static final int[] TX_MULTIPLIER = {30, 31}; - private static final int[] TARGET_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55}; - private static final int[] SOURCE_ADDRESS = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79}; + private static final int[] SOURCE_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55}; + private static final int[] TARGET_ADDRESS = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79}; - private Identifier mTargetAddress; private Identifier mSourceAddress; + private Identifier mTargetAddress; private List mIdentifiers; /** * Constructs a TSBK from the binary message sequence. */ - public RadioUnitMonitorRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public RadioUnitMonitorCommand(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } @@ -45,7 +67,7 @@ public String toString() } /** - * Multipler for a value stored in the radio that determines how long the target address radio will be + * Multiplier for a value stored in the radio that determines how long the target address radio will be * keyed for monitoring. */ public int getTxMultiplier() diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/RoamingAddressCommand.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/RoamingAddressCommand.java similarity index 90% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/RoamingAddressCommand.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/RoamingAddressCommand.java index f187cda44..ba259792d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/RoamingAddressCommand.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/RoamingAddressCommand.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; 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.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.ISPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.ISPMessage; import io.github.dsheirer.module.decode.p25.reference.StackOperation; import java.util.ArrayList; @@ -52,7 +52,7 @@ public class RoamingAddressCommand extends ISPMessage /** * Constructs a TSBK from the binary message sequence. */ - public RoamingAddressCommand(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public RoamingAddressCommand(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SNDCPDataChannelAnnouncementExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SNDCPDataChannelAnnouncementExplicit.java similarity index 91% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SNDCPDataChannelAnnouncementExplicit.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SNDCPDataChannelAnnouncementExplicit.java index 0400ad54a..e08129dfa 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SNDCPDataChannelAnnouncementExplicit.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SNDCPDataChannelAnnouncementExplicit.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,16 +18,16 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import java.util.ArrayList; import java.util.Collections; @@ -54,7 +54,7 @@ public class SNDCPDataChannelAnnouncementExplicit extends OSPMessage implements /** * Constructs a TSBK from the binary message sequence. */ - public SNDCPDataChannelAnnouncementExplicit(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public SNDCPDataChannelAnnouncementExplicit(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SNDCPDataChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SNDCPDataChannelGrant.java similarity index 91% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SNDCPDataChannelGrant.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SNDCPDataChannelGrant.java index c24bc08b6..3ef21cb8e 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SNDCPDataChannelGrant.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SNDCPDataChannelGrant.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -26,10 +26,10 @@ 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.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import java.util.ArrayList; import java.util.List; @@ -55,7 +55,7 @@ public class SNDCPDataChannelGrant extends OSPMessage implements IFrequencyBandR /** * Constructs a TSBK from the binary message sequence. */ - public SNDCPDataChannelGrant(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public SNDCPDataChannelGrant(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SNDCPDataPageRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SNDCPDataPageRequest.java similarity index 90% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SNDCPDataPageRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SNDCPDataPageRequest.java index 5544926dc..cc6541930 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SNDCPDataPageRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SNDCPDataPageRequest.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; import java.util.ArrayList; import java.util.List; @@ -51,7 +51,7 @@ public class SNDCPDataPageRequest extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public SNDCPDataPageRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public SNDCPDataPageRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SecondaryControlChannelBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SecondaryControlChannelBroadcast.java similarity index 63% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SecondaryControlChannelBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SecondaryControlChannelBroadcast.java index 002ba6d11..3264dedc5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SecondaryControlChannelBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SecondaryControlChannelBroadcast.java @@ -1,24 +1,26 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -26,10 +28,10 @@ import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; -import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; import java.util.ArrayList; import java.util.List; @@ -52,14 +54,14 @@ public class SecondaryControlChannelBroadcast extends OSPMessage implements IFre private Identifier mSite; private IChannelDescriptor mChannelA; private IChannelDescriptor mChannelB; - private VoiceServiceOptions mVoiceServiceOptionsA; - private VoiceServiceOptions mVoiceServiceOptionsB; + private SystemServiceClass mSystemServiceClassA; + private SystemServiceClass mSystemServiceClassB; private List mIdentifiers; /** * Constructs a TSBK from the binary message sequence. */ - public SecondaryControlChannelBroadcast(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public SecondaryControlChannelBroadcast(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } @@ -71,11 +73,11 @@ public String toString() sb.append(" RFSS:").append(getRfss()); sb.append(" SITE:").append(getSite()); sb.append(" CHAN A:").append(getChannelA()); - sb.append(" SERVICE OPTIONS:").append(getVoiceServiceOptionsA()); + sb.append(" SERVICE OPTIONS:").append(getSystemServiceClassA()); if(hasChannelB()) { sb.append(" CHAN B:").append(getChannelB()); - sb.append(" SERVICE OPTIONS:").append(getVoiceServiceOptionsB()); + sb.append(" SERVICE OPTIONS:").append(getSystemServiceClassB()); } return sb.toString(); } @@ -110,14 +112,14 @@ public IChannelDescriptor getChannelA() return mChannelA; } - public VoiceServiceOptions getVoiceServiceOptionsA() + public SystemServiceClass getSystemServiceClassA() { - if(mVoiceServiceOptionsA == null) + if(mSystemServiceClassA == null) { - mVoiceServiceOptionsA = new VoiceServiceOptions(getMessage().getInt(SYSTEM_SERVICE_CLASS_A)); + mSystemServiceClassA = new SystemServiceClass(getMessage().getInt(SYSTEM_SERVICE_CLASS_A)); } - return mVoiceServiceOptionsA; + return mSystemServiceClassA; } private boolean hasChannelB() @@ -136,14 +138,14 @@ public IChannelDescriptor getChannelB() return mChannelB; } - public VoiceServiceOptions getVoiceServiceOptionsB() + public SystemServiceClass getSystemServiceClassB() { - if(mVoiceServiceOptionsB == null) + if(mSystemServiceClassB == null) { - mVoiceServiceOptionsB = new VoiceServiceOptions(getMessage().getInt(SYSTEM_SERVICE_CLASS_B)); + mSystemServiceClassB = new SystemServiceClass(getMessage().getInt(SYSTEM_SERVICE_CLASS_B)); } - return mVoiceServiceOptionsB; + return mSystemServiceClassB; } @Override diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SecondaryControlChannelBroadcastExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SecondaryControlChannelBroadcastExplicit.java new file mode 100644 index 000000000..7f44fdd61 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SecondaryControlChannelBroadcastExplicit.java @@ -0,0 +1,140 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; +import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25ExplicitChannel; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; + +import java.util.ArrayList; +import java.util.List; + +/** + * Secondary control channel broadcast - explicit + */ +public class SecondaryControlChannelBroadcastExplicit extends OSPMessage implements IFrequencyBandReceiver +{ + private static final int[] RFSS = {16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] SITE = {24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] TRANSMIT_FREQUENCY_BAND = {32, 33, 34, 35}; + private static final int[] TRANSMIT_CHANNEL_NUMBER = {36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + private static final int[] RESERVED = {48, 49, 50, 51, 52, 53, 54, 55}; + private static final int[] RECEIVE_FREQUENCY_BAND = {56, 57, 58, 59}; + private static final int[] RECEIVE_CHANNEL_NUMBER = {60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71}; + private static final int[] SYSTEM_SERVICE_CLASS = {72, 73, 74, 75, 76, 77, 78, 79}; + + private Identifier mRfss; + private Identifier mSite; + private IChannelDescriptor mChannel; + private SystemServiceClass mSystemServiceClass; + private List mIdentifiers; + + /** + * Constructs a TSBK from the binary message sequence. + */ + public SecondaryControlChannelBroadcastExplicit(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + { + super(dataUnitId, message, nac, timestamp); + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getMessageStub()); + sb.append(" RFSS:").append(getRfss()); + sb.append(" SITE:").append(getSite()); + sb.append(" CHAN:").append(getChannel()); + sb.append(" SERVICE OPTIONS:").append(getSystemServiceClass()); + return sb.toString(); + } + + public Identifier getRfss() + { + if(mRfss == null) + { + mRfss = APCO25Rfss.create(getMessage().getInt(RFSS)); + } + + return mRfss; + } + + public Identifier getSite() + { + if(mSite == null) + { + mSite = APCO25Site.create(getMessage().getInt(SITE)); + } + + return mSite; + } + + public IChannelDescriptor getChannel() + { + if(mChannel == null) + { + mChannel = APCO25ExplicitChannel.create(getMessage().getInt(TRANSMIT_FREQUENCY_BAND), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER), getMessage().getInt(RECEIVE_FREQUENCY_BAND), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER)); + } + + return mChannel; + } + + public SystemServiceClass getSystemServiceClass() + { + if(mSystemServiceClass == null) + { + mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SYSTEM_SERVICE_CLASS)); + } + + return mSystemServiceClass; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getSite()); + mIdentifiers.add(getRfss()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannel()); + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/StatusQuery.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/StatusQuery.java similarity index 88% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/StatusQuery.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/StatusQuery.java index 98bd94541..e66a7f3b1 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/StatusQuery.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/StatusQuery.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -48,7 +48,7 @@ public class StatusQuery extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public StatusQuery(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public StatusQuery(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/StatusUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/StatusUpdate.java similarity index 91% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/StatusUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/StatusUpdate.java index 7a312143c..41cdf0b93 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/StatusUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/StatusUpdate.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,7 +18,7 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; @@ -26,8 +26,8 @@ import io.github.dsheirer.module.decode.p25.identifier.status.APCO25UserStatus; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -53,7 +53,7 @@ public class StatusUpdate extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public StatusUpdate(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public StatusUpdate(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SyncBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SyncBroadcast.java similarity index 95% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SyncBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SyncBroadcast.java index 891b6c4e1..d71847418 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SyncBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SyncBroadcast.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -60,7 +60,7 @@ public class SyncBroadcast extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public SyncBroadcast(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public SyncBroadcast(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SystemServiceBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SystemServiceBroadcast.java similarity index 87% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SystemServiceBroadcast.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SystemServiceBroadcast.java index 41976288c..0e47d11e8 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/SystemServiceBroadcast.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/SystemServiceBroadcast.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.Service; import java.util.Collections; @@ -48,7 +48,7 @@ public class SystemServiceBroadcast extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public SystemServiceBroadcast(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public SystemServiceBroadcast(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/TelephoneInterconnectAnswerRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/TelephoneInterconnectAnswerRequest.java similarity index 72% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/TelephoneInterconnectAnswerRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/TelephoneInterconnectAnswerRequest.java index 2863ada7f..5c5302be7 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/TelephoneInterconnectAnswerRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/TelephoneInterconnectAnswerRequest.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.telephone.APCO25TelephoneNumber; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.Digit; import java.util.ArrayList; @@ -36,7 +56,7 @@ public class TelephoneInterconnectAnswerRequest extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public TelephoneInterconnectAnswerRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public TelephoneInterconnectAnswerRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/TelephoneInterconnectVoiceChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/TelephoneInterconnectVoiceChannelGrant.java similarity index 71% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/TelephoneInterconnectVoiceChannelGrant.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/TelephoneInterconnectVoiceChannelGrant.java index e36e36281..50eef36d5 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/TelephoneInterconnectVoiceChannelGrant.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/TelephoneInterconnectVoiceChannelGrant.java @@ -1,13 +1,33 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; 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.APCO25FromTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -33,7 +53,7 @@ public class TelephoneInterconnectVoiceChannelGrant extends OSPMessage implement /** * Constructs a TSBK from the binary message sequence. */ - public TelephoneInterconnectVoiceChannelGrant(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public TelephoneInterconnectVoiceChannelGrant(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/TelephoneInterconnectVoiceChannelGrantUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/TelephoneInterconnectVoiceChannelGrantUpdate.java similarity index 71% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/TelephoneInterconnectVoiceChannelGrantUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/TelephoneInterconnectVoiceChannelGrantUpdate.java index 611d1be07..7f6503f7e 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/TelephoneInterconnectVoiceChannelGrantUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/TelephoneInterconnectVoiceChannelGrantUpdate.java @@ -1,13 +1,33 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; 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.APCO25AnyTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -33,7 +53,7 @@ public class TelephoneInterconnectVoiceChannelGrantUpdate extends OSPMessage imp /** * Constructs a TSBK from the binary message sequence. */ - public TelephoneInterconnectVoiceChannelGrantUpdate(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public TelephoneInterconnectVoiceChannelGrantUpdate(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitDeRegistrationAcknowledge.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitDeRegistrationAcknowledge.java similarity index 89% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitDeRegistrationAcknowledge.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitDeRegistrationAcknowledge.java index 51d5819cd..83742f4bc 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitDeRegistrationAcknowledge.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitDeRegistrationAcknowledge.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; 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.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -50,7 +50,7 @@ public class UnitDeRegistrationAcknowledge extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnitDeRegistrationAcknowledge(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnitDeRegistrationAcknowledge(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitRegistrationCommand.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitRegistrationCommand.java similarity index 88% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitRegistrationCommand.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitRegistrationCommand.java index c1eecc352..6e2e9db9a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitRegistrationCommand.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitRegistrationCommand.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,14 +18,14 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -48,7 +48,7 @@ public class UnitRegistrationCommand extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnitRegistrationCommand(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnitRegistrationCommand(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitRegistrationResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitRegistrationResponse.java similarity index 90% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitRegistrationResponse.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitRegistrationResponse.java index 930d75256..0bed40d7c 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitRegistrationResponse.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitRegistrationResponse.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,15 +18,15 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; 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.talkgroup.APCO25IdentifierTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.Response; import java.util.ArrayList; @@ -54,7 +54,7 @@ public class UnitRegistrationResponse extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnitRegistrationResponse(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnitRegistrationResponse(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitToUnitAnswerRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitToUnitAnswerRequest.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitToUnitAnswerRequest.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitToUnitAnswerRequest.java index a68e2d753..a8ad66dad 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitToUnitAnswerRequest.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitToUnitAnswerRequest.java @@ -1,11 +1,31 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; import java.util.ArrayList; @@ -31,7 +51,7 @@ public class UnitToUnitAnswerRequest extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnitToUnitAnswerRequest(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnitToUnitAnswerRequest(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitToUnitVoiceChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitToUnitVoiceChannelGrant.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitToUnitVoiceChannelGrant.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitToUnitVoiceChannelGrant.java index fad8531c4..71e3a534b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitToUnitVoiceChannelGrant.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitToUnitVoiceChannelGrant.java @@ -1,4 +1,24 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -6,9 +26,9 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -33,7 +53,7 @@ public class UnitToUnitVoiceChannelGrant extends OSPMessage implements IFrequenc /** * Constructs a TSBK from the binary message sequence. */ - public UnitToUnitVoiceChannelGrant(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnitToUnitVoiceChannelGrant(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitToUnitVoiceChannelGrantUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitToUnitVoiceChannelGrantUpdate.java similarity index 69% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitToUnitVoiceChannelGrantUpdate.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitToUnitVoiceChannelGrantUpdate.java index 27a1413fb..9e93e2807 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/standard/osp/UnitToUnitVoiceChannelGrantUpdate.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnitToUnitVoiceChannelGrantUpdate.java @@ -1,4 +1,24 @@ -package io.github.dsheirer.module.decode.p25.message.tsbk.standard.osp; +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.channel.IChannelDescriptor; @@ -6,9 +26,9 @@ import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; -import io.github.dsheirer.module.decode.p25.message.IFrequencyBandReceiver; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.ArrayList; import java.util.List; @@ -33,7 +53,7 @@ public class UnitToUnitVoiceChannelGrantUpdate extends OSPMessage implements IFr /** * Constructs a TSBK from the binary message sequence. */ - public UnitToUnitVoiceChannelGrantUpdate(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnitToUnitVoiceChannelGrantUpdate(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnknownOSPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnknownOSPMessage.java new file mode 100644 index 000000000..279b3ec28 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/standard/osp/UnknownOSPMessage.java @@ -0,0 +1,58 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; + +import java.util.Collections; +import java.util.List; + +/** + * Unknown/Unrecognized opcode message. + */ +public class UnknownOSPMessage extends OSPMessage +{ + /** + * Constructs a TSBK from the binary message sequence. + */ + public UnknownOSPMessage(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + { + super(dataUnitId, message, nac, timestamp); + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getMessageStub()); + sb.append(" **UNRECOGNIZED OSP OPCODE**"); + sb.append(" MSG:").append(getMessage().toHexString()); + return sb.toString(); + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/unknown/isp/UnknownVendorISPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/unknown/isp/UnknownVendorISPMessage.java similarity index 81% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/unknown/isp/UnknownVendorISPMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/unknown/isp/UnknownVendorISPMessage.java index f983c0f5d..b7be71c7e 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/unknown/isp/UnknownVendorISPMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/unknown/isp/UnknownVendorISPMessage.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.unknown.isp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.unknown.isp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.Collections; import java.util.List; @@ -36,7 +36,7 @@ public class UnknownVendorISPMessage extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnknownVendorISPMessage(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnknownVendorISPMessage(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/unknown/osp/UnknownVendorOSPMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/unknown/osp/UnknownVendorOSPMessage.java similarity index 81% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/unknown/osp/UnknownVendorOSPMessage.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/unknown/osp/UnknownVendorOSPMessage.java index a4a1e7407..925db3fc4 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/unknown/osp/UnknownVendorOSPMessage.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/tsbk/unknown/osp/UnknownVendorOSPMessage.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.tsbk.unknown.osp; +package io.github.dsheirer.module.decode.p25.phase1.message.tsbk.unknown.osp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.tsbk.OSPMessage; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.OSPMessage; import java.util.Collections; import java.util.List; @@ -36,7 +36,7 @@ public class UnknownVendorOSPMessage extends OSPMessage /** * Constructs a TSBK from the binary message sequence. */ - public UnknownVendorOSPMessage(DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) + public UnknownVendorOSPMessage(P25P1DataUnitID dataUnitId, CorrectedBinaryMessage message, int nac, long timestamp) { super(dataUnitId, message, nac, timestamp); } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/vselp/VSELP1Message.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/vselp/VSELP1Message.java new file mode 100644 index 000000000..5da1e6883 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/vselp/VSELP1Message.java @@ -0,0 +1,61 @@ +/* + * ****************************************************************************** + * sdrtrunk + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.module.decode.p25.phase1.message.vselp; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +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 java.util.Collections; +import java.util.List; + +public class VSELP1Message extends P25Message +{ + /** + * Motorola VSELP audio message 1 - not implemented. + */ + public VSELP1Message(CorrectedBinaryMessage message, int nac, long timestamp) + { + super(message, nac, timestamp); + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getMessageStub()); + sb.append(" MSG:").append(getMessage().toHexString()); + return sb.toString(); + } + + @Override + public P25P1DataUnitID getDUID() + { + return P25P1DataUnitID.VSELP1; + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/vselp/VSELP2Message.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/vselp/VSELP2Message.java similarity index 83% rename from src/main/java/io/github/dsheirer/module/decode/p25/message/vselp/VSELP2Message.java rename to src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/vselp/VSELP2Message.java index 6dd854cb5..8f71a4686 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/message/vselp/VSELP2Message.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/message/vselp/VSELP2Message.java @@ -1,7 +1,7 @@ /* * ****************************************************************************** * sdrtrunk - * Copyright (C) 2014-2018 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 @@ -18,12 +18,12 @@ * ***************************************************************************** */ -package io.github.dsheirer.module.decode.p25.message.vselp; +package io.github.dsheirer.module.decode.p25.phase1.message.vselp; import io.github.dsheirer.bits.CorrectedBinaryMessage; import io.github.dsheirer.identifier.Identifier; -import io.github.dsheirer.module.decode.p25.message.P25Message; -import io.github.dsheirer.module.decode.p25.reference.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.P25P1DataUnitID; +import io.github.dsheirer.module.decode.p25.phase1.message.P25Message; import java.util.Collections; import java.util.List; @@ -48,9 +48,9 @@ public String toString() } @Override - public DataUnitID getDUID() + public P25P1DataUnitID getDUID() { - return DataUnitID.VSELP2; + return P25P1DataUnitID.VSELP2; } @Override diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/DecodeConfigP25Phase2.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/DecodeConfigP25Phase2.java new file mode 100644 index 000000000..0535125d9 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/DecodeConfigP25Phase2.java @@ -0,0 +1,87 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2; + + +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.module.decode.p25.phase2.enumeration.ScrambleParameters; +import io.github.dsheirer.source.tuner.channel.ChannelSpecification; + +public class DecodeConfigP25Phase2 extends DecodeConfiguration +{ + private ScrambleParameters mScrambleParameters; + private boolean mAutoDetectScrambleParameters; + + public DecodeConfigP25Phase2() + { + } + + @JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance") + public DecoderType getDecoderType() + { + return DecoderType.P25_PHASE2; + } + + /** + * Source channel specification for this decoder + */ + @JsonIgnore + @Override + public ChannelSpecification getChannelSpecification() + { + return new ChannelSpecification(50000.0, 12500, 6500.0, 7200.0); + } + + @Override + public int getTimeslotCount() + { + return 2; + } + + /** + * Optional scramble (ie randomizer) parameters to use for the channel. + */ + @JacksonXmlProperty(localName = "scramble_parameters") + public ScrambleParameters getScrambleParameters() + { + return mScrambleParameters; + } + + public void setScrambleParameters(ScrambleParameters scrambleParameters) + { + mScrambleParameters = scrambleParameters; + } + + @JacksonXmlProperty(isAttribute = true, localName = "auto_detect_scramble_parameters") + public boolean isAutoDetectScrambleParameters() + { + return mAutoDetectScrambleParameters; + } + + public void setAutoDetectScrambleParameters(boolean autoDetect) + { + mAutoDetectScrambleParameters = autoDetect; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/DibitDelayBuffer.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/DibitDelayBuffer.java new file mode 100644 index 000000000..29c89fb6b --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/DibitDelayBuffer.java @@ -0,0 +1,216 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.bits.BitSetFullException; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.dsp.symbol.Dibit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Circular buffer for storing and accessing dibits. + */ +public class DibitDelayBuffer +{ + private final static Logger mLog = LoggerFactory.getLogger(DibitDelayBuffer.class); + + protected Dibit[] mBuffer; + protected int mPointer; + + /** + * Constructs a dibit delay buffer of the specified length + */ + public DibitDelayBuffer(int length) + { + mBuffer = new Dibit[length]; + + //Preload the buffer to avoid null pointers + for(int x = 0; x < length; x++) + { + mBuffer[x] = Dibit.D00_PLUS_1; + } + } + + /** + * Returns an ordered buffer of the internal circular buffer contents. + */ + public Dibit[] getBuffer() + { + Dibit[] transferBuffer = new Dibit[mBuffer.length]; + + int transferBufferPointer = 0; + int bufferPointer = mPointer; + + while(transferBufferPointer < transferBuffer.length) + { + transferBuffer[transferBufferPointer++] = mBuffer[bufferPointer++]; + + if(bufferPointer >= mBuffer.length) + { + bufferPointer = 0; + } + } + + return transferBuffer; + } + + public Dibit[] getBuffer(int start, int length) + { + Dibit[] transferBuffer = new Dibit[length]; + + int transferBufferPointer = 0; + int bufferPointer = (mPointer + start) % mBuffer.length; + + while(transferBufferPointer < transferBuffer.length) + { + transferBuffer[transferBufferPointer++] = mBuffer[bufferPointer++]; + + if(bufferPointer >= mBuffer.length) + { + bufferPointer = 0; + } + } + + return transferBuffer; + } + + /** + * Extracts a corrected binary message from the dibit buffer + * + * @param start dibit index where 0 is the oldest dibit and the newest dibit is buffer length - 1 + * @param dibitLength number of dibits to include in the message, making the message length = dibitLength * 2 + * @return corrected binary message + */ + public CorrectedBinaryMessage getMessage(int start, int dibitLength) + { + CorrectedBinaryMessage message = new CorrectedBinaryMessage(dibitLength * 2); + + int dibitCount = 0; + int bufferPointer = (mPointer + start) % mBuffer.length; + + try + { + while(dibitCount < dibitLength) + { + Dibit dibit = mBuffer[bufferPointer++]; + message.add(dibit.getBit1()); + message.add(dibit.getBit2()); + dibitCount++; + + if(bufferPointer >= mBuffer.length) + { + bufferPointer = 0; + } + } + } + catch(BitSetFullException e) + { + //This shouldn't happen + mLog.error("Bit set full ??", e); + } + + return message; + } + + public int[] getBufferAsArray() + { + Dibit[] dibits = getBuffer(); + + int[] bits = new int[dibits.length * 2]; + + for(int x = 0; x < dibits.length; x++) + { + if(dibits[x].getBit1()) + { + bits[x * 2] = 1; + } + if(dibits[x].getBit2()) + { + bits[x * 2 + 1] = 1; + } + } + + return bits; + } + + /** + * Places the dibit into the internal circular buffer, overwriting the oldest dibit. + */ + public void put(Dibit dibit) + { + mBuffer[mPointer++] = dibit; + + if(mPointer >= mBuffer.length) + { + mPointer = 0; + } + } + + /** + * Places the dibit into the internal circular buffer, overwriting and returning the + * oldest dibit. + */ + public Dibit getAndPut(Dibit dibit) + { + Dibit toReturn = mBuffer[mPointer]; + put(dibit); + return toReturn; + } + + public void log() + { + StringBuilder sb = new StringBuilder(); + + int counter = 0; + int pointer = mPointer; + + while(counter < mBuffer.length) + { + sb.append(mBuffer[pointer].getBit1() ? "1" : "0"); + sb.append(mBuffer[pointer++].getBit2() ? "1" : "0"); + + if(pointer >= mBuffer.length) + { + pointer = 0; + } + + counter++; + } + mLog.debug("BUFFER: " + sb.toString() + " Length:" + mBuffer.length); + } + + public static void main(String[] args) + { + Dibit[] test = { + Dibit.D01_PLUS_3,Dibit.D01_PLUS_3,Dibit.D01_PLUS_3,Dibit.D11_MINUS_3, + Dibit.D01_PLUS_3,Dibit.D01_PLUS_3,Dibit.D11_MINUS_3,Dibit.D01_PLUS_3, + Dibit.D01_PLUS_3,Dibit.D01_PLUS_3,Dibit.D01_PLUS_3,Dibit.D11_MINUS_3, + Dibit.D11_MINUS_3,Dibit.D11_MINUS_3,Dibit.D01_PLUS_3,Dibit.D11_MINUS_3, + Dibit.D11_MINUS_3,Dibit.D11_MINUS_3,Dibit.D11_MINUS_3,Dibit.D01_PLUS_3}; + + int bitErrors = P25P2SyncPattern.getBitErrorCount(test); + + mLog.debug("Bit Errors:" + bitErrors); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/IP25P2DataUnitDetectListener.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/IP25P2DataUnitDetectListener.java new file mode 100644 index 000000000..fa05a47ce --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/IP25P2DataUnitDetectListener.java @@ -0,0 +1,48 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID; + +/** + * Listener interface to be notified each time a P25 sync pattern and data unit has been detected + * and the data unit is correct after error detection and correction and/or when the sync has been lost. + */ +public interface IP25P2DataUnitDetectListener +{ + /** + * Indicates that a P25 sync has been detected and a P25 data unit was successfully decoded. + * @param dataUnitID that was contained in the detected NID + * @param nac or Network Access Code that was contained in the detected NID + * @param discardedDibits prior to detecting the P25 sync pattern + * @param bitErrors detected and corrected from both the sync pattern and the NID. + * @param correctedNid bits corrected by the BCH error correction code (temporary until message parsers are updated + */ + void dataUnitDetected(DataUnitID dataUnitID, int nac, int bitErrors, int discardedDibits, int[] correctedNid); + + /** + * Indicates that sync has been lost on the dibit stream + * + * @param bitsProcessed since the last sync detect + */ + void syncLost(int bitsProcessed); +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2Decoder.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2Decoder.java new file mode 100644 index 000000000..46b890fc1 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2Decoder.java @@ -0,0 +1,226 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.dsp.symbol.Dibit; +import io.github.dsheirer.dsp.symbol.DibitToByteBufferAssembler; +import io.github.dsheirer.module.decode.Decoder; +import io.github.dsheirer.module.decode.DecoderType; +import io.github.dsheirer.sample.Broadcaster; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.IReusableByteBufferProvider; +import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener; +import io.github.dsheirer.sample.buffer.ReusableByteBuffer; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.source.ISourceEventListener; +import io.github.dsheirer.source.ISourceEventProvider; +import io.github.dsheirer.source.SourceEvent; + +/** + * Base P25 Phase 2 Decoder + */ +public abstract class P25P2Decoder extends Decoder implements ISourceEventListener, ISourceEventProvider, + IReusableComplexBufferListener, Listener, IReusableByteBufferProvider +{ + private double mSampleRate; + private Broadcaster mDibitBroadcaster = new Broadcaster<>(); + private DibitToByteBufferAssembler mByteBufferAssembler = new DibitToByteBufferAssembler(300); + private P25P2MessageProcessor mMessageProcessor; + private Listener mSourceEventListener; + private double mSymbolRate; + + public P25P2Decoder(double symbolRate) + { + mSymbolRate = symbolRate; + mMessageProcessor = new P25P2MessageProcessor(); + mMessageProcessor.setMessageListener(getMessageListener()); + getDibitBroadcaster().addListener(mByteBufferAssembler); + } + + /** + * Assembler for packaging Dibit stream into reusable byte buffers. + */ + protected Broadcaster getDibitBroadcaster() + { + return mDibitBroadcaster; + } + + /** + * Implements the IByteBufferProvider interface - delegates to the byte buffer assembler + */ + @Override + public void setBufferListener(Listener listener) + { + mByteBufferAssembler.setBufferListener(listener); + } + + /** + * Implements the IByteBufferProvider interface - delegates to the byte buffer assembler + */ + @Override + public void removeBufferListener(Listener listener) + { + mByteBufferAssembler.removeBufferListener(listener); + } + + /** + * Implements the IByteBufferProvider interface - delegates to the byte buffer assembler + */ + @Override + public boolean hasBufferListeners() + { + return mByteBufferAssembler.hasBufferListeners(); + } + + protected double getSymbolRate() + { + return mSymbolRate; + } + + /** + * Current sample rate for this decoder + */ + protected double getSampleRate() + { + return mSampleRate; + } + + /** + * Sets current sample rate for this decoder + */ + public void setSampleRate(double sampleRate) + { + if(sampleRate <= getSymbolRate() * 2) + { + throw new IllegalArgumentException("Sample rate [" + sampleRate + "] must be > 12000 (2 * " + + getSymbolRate() + " symbol rate)"); + } + + mSampleRate = sampleRate; + } + + /** + * Samples per symbol based on current sample rate and symbol rate. + */ + public float getSamplesPerSymbol() + { + return (float)(getSampleRate() / getSymbolRate()); + } + + public void dispose() + { + super.dispose(); + + mMessageProcessor.dispose(); + mMessageProcessor = null; + } + + /** + * Sets the source event listener to receive source events from this decoder. + */ + @Override + public void setSourceEventListener(Listener listener) + { + mSourceEventListener = listener; + } + + /** + * Removes a registered source event listener from receiving source events from this decoder + */ + @Override + public void removeSourceEventListener() + { + mSourceEventListener = null; + } + + @Override + public Listener getSourceEventListener() + { + return new Listener() + { + @Override + public void receive(SourceEvent sourceEvent) + { + process(sourceEvent); + } + }; + } + + /** + * Sub-class processing of received source events + * + * @param sourceEvent + */ + protected abstract void process(SourceEvent sourceEvent); + + /** + * Broadcasts the source event to an optional registered listener. This method should primarily be used to + * issue frequency correction requests to the channel source. + * + * @param sourceEvent to broadcast + */ + public void broadcast(SourceEvent sourceEvent) + { + if(mSourceEventListener != null) + { + mSourceEventListener.receive(sourceEvent); + } + } + + /** + * Listener interface to receive reusable complex buffers + */ + @Override + public Listener getReusableComplexBufferListener() + { + return P25P2Decoder.this; + } + + /** + * Starts the decoder + */ + @Override + public void start() + { + //No-op + } + + /** + * Stops the decoder + */ + @Override + public void stop() + { + //No-op + } + + @Override + public DecoderType getDecoderType() + { + return DecoderType.P25_PHASE2; + } + + protected P25P2MessageProcessor getMessageProcessor() + { + return mMessageProcessor; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderEditor.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderEditor.java new file mode 100644 index 000000000..6e3f1ccc0 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderEditor.java @@ -0,0 +1,276 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.controller.channel.Channel; +import io.github.dsheirer.gui.editor.Editor; +import io.github.dsheirer.gui.editor.EditorValidationException; +import io.github.dsheirer.gui.editor.ValidatingEditor; +import io.github.dsheirer.module.decode.AuxDecodeConfigurationEditor; +import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration; +import io.github.dsheirer.module.decode.config.DecodeConfiguration; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters; +import io.github.dsheirer.source.SourceConfigurationEditor; +import io.github.dsheirer.source.config.SourceConfigTuner; +import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency; +import io.github.dsheirer.source.config.SourceConfiguration; +import net.miginfocom.swing.MigLayout; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.swing.JCheckBox; +import javax.swing.JFormattedTextField; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Editor panel for P25 Phase II decoder configuration + */ +public class P25P2DecoderEditor extends ValidatingEditor +{ + private final static Logger mLog = LoggerFactory.getLogger(P25P2DecoderEditor.class); + + private static final long serialVersionUID = 1L; + + private JCheckBox mAutoDetectCheckBox; + private JFormattedTextField mWacnText; + private JFormattedTextField mSystemText; + private JFormattedTextField mNacText; + + public P25P2DecoderEditor() + { + init(); + } + + private void init() + { + setLayout(new MigLayout("insets 0 0 0 0,wrap 2", "[right][grow,fill]", "")); + + mAutoDetectCheckBox = new JCheckBox("Auto-Detect System Settings"); + mAutoDetectCheckBox.setToolTipText("Auto-detect WACN, SYSTEM and NAC for systems that broadcast this information."); + mAutoDetectCheckBox.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + mWacnText.setEnabled(!mAutoDetectCheckBox.isSelected()); + mSystemText.setEnabled(!mAutoDetectCheckBox.isSelected()); + mNacText.setEnabled(!mAutoDetectCheckBox.isSelected()); + setModified(true); + } + }); + add(new JLabel(" ")); + add(mAutoDetectCheckBox); + + add(new JLabel("WACN:")); + mWacnText = new JFormattedTextField(); + mWacnText.setToolTipText("Wide Area Communications Network (WACN) value in range: 0 - 1,048,575. Set to 0 for auto-detect"); + mWacnText.setValue(Integer.valueOf(0)); + mWacnText.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + setModified(true); + } + }); + add(mWacnText); + + add(new JLabel("SYSTEM:")); + mSystemText = new JFormattedTextField(); + mSystemText.setToolTipText("System code in range: 0 - 4,095. Set to 0 for auto-detect"); + mSystemText.setValue(Integer.valueOf(0)); + mSystemText.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + setModified(true); + } + }); + add(mSystemText); + + add(new JLabel("NAC:")); + mNacText = new JFormattedTextField(); + mSystemText.setToolTipText("Network Access Code (NAC): 0 - 4,095. Set to 0 for auto-detect"); + mNacText.setValue(Integer.valueOf(0)); + mNacText.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + setModified(true); + } + }); + add(mNacText); + } + + @Override + public void save() + { + if(hasItem() && isModified()) + { + DecodeConfigP25Phase2 p25 = new DecodeConfigP25Phase2(); + + p25.setAutoDetectScrambleParameters(mAutoDetectCheckBox.isSelected()); + + int wacn = ((Number)mWacnText.getValue()).intValue(); + + if(wacn < 0 || wacn > 0xFFFFF) + { + JOptionPane.showConfirmDialog(P25P2DecoderEditor.this, "WACN [" + wacn + + "] must be in range: 0 - 1,048,575. Please change and click 'Save' or a default value of 0 will " + + "be used", "WACN Value Error", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE); + + wacn = 0; + } + + int system = ((Number)mSystemText.getValue()).intValue(); + + if(system < 0 || system > 0xFFF) + { + JOptionPane.showConfirmDialog(P25P2DecoderEditor.this, "SYSTEM [" + system + + "] must be in range: 0 - 4,095. Please change and click 'Save' or a default value of 0 will " + + "be used", "SYSTEM Value Error", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE); + + system = 0; + } + + int nac = ((Number)mNacText.getValue()).intValue(); + + if(nac < 0 || nac > 0xFFF) + { + JOptionPane.showConfirmDialog(P25P2DecoderEditor.this, "NAC [" + nac + + "] must be in range: 0 - 4,095. Please change and click 'Save' or a default value of 0 will " + + "be used", "NAC Value Error", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE); + + nac = 0; + } + + if(wacn != 0 && system != 0 && nac != 0) + { + p25.setScrambleParameters(new ScrambleParameters(wacn, system, nac)); + } + + getItem().setDecodeConfiguration(p25); + } + + setModified(false); + } + + @Override + public void validate(Editor editor) throws EditorValidationException + { + /** + * Enforce CQPSK modulation uses a Tuner Source for I/Q sample data + */ + if(editor instanceof SourceConfigurationEditor) + { + SourceConfiguration config = ((SourceConfigurationEditor)editor).getSourceConfiguration(); + + if(!(config instanceof SourceConfigTuner || config instanceof SourceConfigTunerMultipleFrequency)) + { + throw new EditorValidationException(editor, + "

LSM Simulcast

" + + "

P25 Phase II decoder can only be used with a tuner source.

"); + } + } + else if(editor instanceof AuxDecodeConfigurationEditor) + { + AuxDecodeConfiguration config = ((AuxDecodeConfigurationEditor)editor).getConfiguration(); + + if(config != null && !config.getAuxDecoders().isEmpty()) + { + throw new EditorValidationException(editor, + "

Auxilary Decoders

" + + "

The auxiliary decoders work with analog audio and are not " + + "compatible with the P25 Decoder. Please uncheck any auxiliary " + + "decoders that you have selected for this channel

"); + } + } + } + + private void setControlsEnabled(boolean enabled) + { + mWacnText.setEnabled(enabled); + mSystemText.setEnabled(enabled); + mNacText.setEnabled(enabled); + mAutoDetectCheckBox.setEnabled(enabled); + } + + @Override + public void setItem(Channel item) + { + super.setItem(item); + + if(hasItem()) + { + setControlsEnabled(true); + + DecodeConfiguration config = getItem().getDecodeConfiguration(); + + if(config instanceof DecodeConfigP25Phase2) + { + DecodeConfigP25Phase2 p25 = (DecodeConfigP25Phase2)config; + + ScrambleParameters scrambleParameters = p25.getScrambleParameters(); + + if(scrambleParameters != null) + { + mWacnText.setValue(scrambleParameters.getWACN()); + mSystemText.setValue(scrambleParameters.getSystem()); + mNacText.setValue(scrambleParameters.getNAC()); + } + + boolean autoDetect = p25.isAutoDetectScrambleParameters(); + mAutoDetectCheckBox.setSelected(autoDetect); + mWacnText.setEnabled(!autoDetect); + mSystemText.setEnabled(!autoDetect); + mNacText.setEnabled(!autoDetect); + + setModified(false); + } + else + { + mAutoDetectCheckBox.setSelected(false); + mWacnText.setEnabled(true); + mWacnText.setValue(0); + mSystemText.setEnabled(true); + mSystemText.setValue(0); + mNacText.setEnabled(true); + mNacText.setValue(0); + setModified(true); + } + } + else + { + mWacnText.setValue(0); + mSystemText.setValue(0); + mNacText.setValue(0); + mAutoDetectCheckBox.setSelected(false); + setModified(false); + setControlsEnabled(false); + } + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSK.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSK.java new file mode 100644 index 000000000..0b2b754ab --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSK.java @@ -0,0 +1,277 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.dsp.filter.FilterFactory; +import io.github.dsheirer.dsp.filter.design.FilterDesignException; +import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification; +import io.github.dsheirer.dsp.filter.fir.complex.ComplexFIRFilter2; +import io.github.dsheirer.dsp.gain.ComplexFeedForwardGainControl; +import io.github.dsheirer.dsp.psk.DQPSKGardnerDemodulator; +import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer; +import io.github.dsheirer.dsp.psk.pll.CostasLoop; +import io.github.dsheirer.dsp.psk.pll.PLLGain; +import io.github.dsheirer.identifier.Form; +import io.github.dsheirer.identifier.IdentifierUpdateListener; +import io.github.dsheirer.identifier.IdentifierUpdateNotification; +import io.github.dsheirer.module.decode.DecoderType; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters; +import io.github.dsheirer.protocol.Protocol; +import io.github.dsheirer.record.binary.BinaryRecorder; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.source.SourceEvent; +import io.github.dsheirer.source.wave.ComplexWaveSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; + +/** + * P25 Phase 2 HDQPSK 2-timeslot Decoder + */ +public class P25P2DecoderHDQPSK extends P25P2Decoder implements IdentifierUpdateListener +{ + private final static Logger mLog = LoggerFactory.getLogger(P25P2DecoderHDQPSK.class); + + protected static final float SYMBOL_TIMING_GAIN = 0.01f; + protected InterpolatingSampleBuffer mInterpolatingSampleBuffer; + protected DQPSKGardnerDemodulator mQPSKDemodulator; + protected CostasLoop mCostasLoop; + protected P25P2MessageFramer mMessageFramer; + private ComplexFeedForwardGainControl mAGC = new ComplexFeedForwardGainControl(32); + private Map mBasebandFilters = new HashMap<>(); + private ComplexFIRFilter2 mBasebandFilter; + private DecodeConfigP25Phase2 mDecodeConfigP25Phase2; + + public P25P2DecoderHDQPSK(DecodeConfigP25Phase2 decodeConfigP25Phase2) + { + super(6000.0); + setSampleRate(25000.0); + mDecodeConfigP25Phase2 = decodeConfigP25Phase2; + } + + public void setSampleRate(double sampleRate) + { + super.setSampleRate(sampleRate); + + mBasebandFilter = new ComplexFIRFilter2(getBasebandFilter()); + mCostasLoop = new CostasLoop(getSampleRate(), getSymbolRate()); + mCostasLoop.setPLLGain(PLLGain.LEVEL_8); + mInterpolatingSampleBuffer = new InterpolatingSampleBuffer(getSamplesPerSymbol(), SYMBOL_TIMING_GAIN); + mQPSKDemodulator = new DQPSKGardnerDemodulator(mCostasLoop, mInterpolatingSampleBuffer); + + if(mMessageFramer != null) + { + getDibitBroadcaster().removeListener(mMessageFramer); + } + + //The Costas Loop receives symbol-inversion correction requests when detected. + //The PLL gain monitor receives sync detect/loss signals from the message framer + mMessageFramer = new P25P2MessageFramer(mCostasLoop, DecoderType.P25_PHASE2.getProtocol().getBitRate()); + mMessageFramer.setListener(getMessageProcessor()); + mMessageFramer.setSampleRate(sampleRate); + + mQPSKDemodulator.setSymbolListener(getDibitBroadcaster()); + getDibitBroadcaster().addListener(mMessageFramer); + } + + /** + * Primary method for processing incoming complex sample buffers + * @param reusableComplexBuffer containing channelized complex samples + */ + @Override + public void receive(ReusableComplexBuffer reusableComplexBuffer) + { + //User accounting of the incoming buffer is handled by the filter + ReusableComplexBuffer basebandFiltered = filter(reusableComplexBuffer); + + //User accounting of the incoming buffer is handled by the gain filter + ReusableComplexBuffer gainApplied = mAGC.filter(basebandFiltered); + + mMessageFramer.setCurrentTime(reusableComplexBuffer.getTimestamp()); + + //User accounting of the filtered buffer is handled by the demodulator + mQPSKDemodulator.receive(gainApplied); + } + + /** + * Filters the complex buffer and returns a new reusable complex buffer with the filtered contents. + * @param reusableComplexBuffer to filter + * @return filtered complex buffer + */ + protected ReusableComplexBuffer filter(ReusableComplexBuffer reusableComplexBuffer) + { + //User accounting of the incoming buffer is handled by the filter + return mBasebandFilter.filter(reusableComplexBuffer); + } + + /** + * Constructs a baseband filter for this decoder using the current sample rate + */ + private float[] getBasebandFilter() + { + //Attempt to reuse a cached (ie already-designed) filter if available + float[] filter = mBasebandFilters.get(getSampleRate()); + + if(filter == null) + { + FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder() + .sampleRate(50000.0) + .passBandCutoff(6500) + .passBandAmplitude(1.0) + .passBandRipple(0.005) + .stopBandAmplitude(0.0) + .stopBandStart(7200) + .stopBandRipple(0.01) + .build(); + + try + { + filter = FilterFactory.getTaps(specification); + } + catch(FilterDesignException fde) + { + mLog.error("Couldn't design low pass baseband filter for sample rate: " + getSampleRate()); + } + + if(filter != null) + { + mBasebandFilters.put(getSampleRate(), filter); + } + else + { + throw new IllegalStateException("Couldn't design a C4FM baseband filter for sample rate: " + getSampleRate()); + } + } + + return filter; + } + + public void dispose() + { + super.dispose(); + + mBasebandFilter.dispose(); + mBasebandFilter = null; + + mMessageFramer = null; + } + + @Override + protected void process(SourceEvent sourceEvent) + { + switch(sourceEvent.getEvent()) + { + case NOTIFICATION_SAMPLE_RATE_CHANGE: + mCostasLoop.reset(); + setSampleRate(sourceEvent.getValue().doubleValue()); + break; + case NOTIFICATION_FREQUENCY_CORRECTION_CHANGE: + //Reset the PLL if/when the tuner PPM changes so that we can re-lock + mCostasLoop.reset(); + break; + } + } + + /** + * Resets this decoder to prepare for processing a new channel + */ + @Override + public void reset() + { + mCostasLoop.reset(); + } + + @Override + public void start() + { + super.start(); + + //Refresh the scramble parameters each time we start in case they change + if(mDecodeConfigP25Phase2 != null && mDecodeConfigP25Phase2.getScrambleParameters() != null && + !mDecodeConfigP25Phase2.isAutoDetectScrambleParameters()) + { + mMessageFramer.setScrambleParameters(mDecodeConfigP25Phase2.getScrambleParameters()); + } + } + + public static void main(String[] args) + { + String path = "/media/denny/500G1EXT4/RadioRecordings/APCO25P2/CNYICC/"; + String input = "CNYICC_Rome_CNYICC_154_250_baseband_20190322_180331_good.wav"; + String output = "CNYICC_ROME_154_250_8"; + + ScrambleParameters scrambleParameters = new ScrambleParameters(781824, 686, 677); //CNYICC + DecodeConfigP25Phase2 decodeConfigP25Phase2 = new DecodeConfigP25Phase2(); + decodeConfigP25Phase2.setScrambleParameters(scrambleParameters); + + P25P2DecoderHDQPSK decoder = new P25P2DecoderHDQPSK(decodeConfigP25Phase2); + BinaryRecorder recorder = new BinaryRecorder(Path.of(path), output, Protocol.APCO25_PHASE2); + decoder.setBufferListener(recorder.getReusableByteBufferListener()); + recorder.start(); + + File file = new File(path + input); + + boolean running = true; + + try(ComplexWaveSource source = new ComplexWaveSource(file)) + { + decoder.setSampleRate(50000.0); + source.setListener(decoder); + source.start(); + + while(running) + { + source.next(200, true); + } + } + catch(IOException e) + { + mLog.error("Error", e); + running = false; + } + + recorder.stop(); + } + + @Override + public Listener getIdentifierUpdateListener() + { + return new Listener() + { + @Override + public void receive(IdentifierUpdateNotification identifierUpdateNotification) + { + if(identifierUpdateNotification.getIdentifier().getForm() == Form.SCRAMBLE_PARAMETERS && mMessageFramer != null) + { + ScrambleParameters scrambleParameters = (ScrambleParameters)identifierUpdateNotification.getIdentifier().getValue(); + mMessageFramer.setScrambleParameters(scrambleParameters); + } + } + }; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSKInstrumented.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSKInstrumented.java new file mode 100644 index 000000000..f52280200 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderHDQPSKInstrumented.java @@ -0,0 +1,138 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.dsp.psk.DQPSKGardnerDemodulatorInstrumented; +import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented; +import io.github.dsheirer.dsp.psk.SymbolDecisionData; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.sample.complex.Complex; + +public class P25P2DecoderHDQPSKInstrumented extends P25P2DecoderHDQPSK +{ + private Listener mPLLPhaseErrorListener; + private Listener mPLLFrequencyListener; + private Listener mSamplesPerSymbolListener; + private Listener mComplexSymbolListener; + private Listener mFilteredSymbolListener; + private Listener mSymbolDecisionDataListener; + + /** + * Instrumented version of the P25 C4FM decoder that supports registering listeners to provide access to data as + * it is being processed by the decoder. + */ + public P25P2DecoderHDQPSKInstrumented(DecodeConfigP25Phase2 decodeConfigP25Phase2) + { + super((decodeConfigP25Phase2)); + } + + /** + * Demodulator + */ + public DQPSKGardnerDemodulatorInstrumented getDemodulator() + { + return (DQPSKGardnerDemodulatorInstrumented)mQPSKDemodulator; + } + + /** + * Overrides the filter method so that we can capture the filtered samples for instrumentation + */ + protected ReusableComplexBuffer filter(ReusableComplexBuffer reusableComplexBuffer) + { + ReusableComplexBuffer filtered = super.filter(reusableComplexBuffer); + + if(mFilteredSymbolListener != null) + { + filtered.incrementUserCount(); + mFilteredSymbolListener.receive(filtered); + } + + return filtered; + } + + /** + * Instrumented interpolating sample buffer + */ + public InterpolatingSampleBufferInstrumented getSampleBuffer() + { + return (InterpolatingSampleBufferInstrumented)mInterpolatingSampleBuffer; + } + + /** + * Overrides this method so we can correctly configure for instrumented operations + */ + public void setSampleRate(double sampleRate) + { + super.setSampleRate(sampleRate); + + InterpolatingSampleBufferInstrumented instrumentedBuffer = + new InterpolatingSampleBufferInstrumented(getSamplesPerSymbol(), SYMBOL_TIMING_GAIN); + mInterpolatingSampleBuffer = instrumentedBuffer; + + DQPSKGardnerDemodulatorInstrumented instrumented = new DQPSKGardnerDemodulatorInstrumented(mCostasLoop, instrumentedBuffer, getSampleRate()); + mQPSKDemodulator = instrumented; + + instrumented.setComplexSymbolListener(mComplexSymbolListener); + instrumented.setPLLErrorListener(mPLLPhaseErrorListener); + instrumented.setPLLFrequencyListener(mPLLFrequencyListener); + instrumented.setSymbolDecisionDataListener(mSymbolDecisionDataListener); + instrumented.setSamplesPerSymbolListener(mSamplesPerSymbolListener); + instrumented.setSymbolListener(getDibitBroadcaster()); + getDibitBroadcaster().addListener(mMessageFramer); + } + + public void setComplexSymbolListener(Listener listener) + { + mComplexSymbolListener = listener; + getDemodulator().setComplexSymbolListener(listener); + } + + public void setPLLPhaseErrorListener(Listener listener) + { + mPLLPhaseErrorListener = listener; + getDemodulator().setPLLErrorListener(listener); + } + + public void setPLLFrequencyListener(Listener listener) + { + mPLLFrequencyListener = listener; + getDemodulator().setPLLFrequencyListener(listener); + } + + public void setFilteredBufferListener(Listener listener) + { + mFilteredSymbolListener = listener; + } + + public void setSymbolDecisionDataListener(Listener listener) + { + mSymbolDecisionDataListener = listener; + getDemodulator().setSymbolDecisionDataListener(listener); + } + + public void setSamplesPerSymbolListener(Listener listener) + { + mSamplesPerSymbolListener = listener; + getDemodulator().setSamplesPerSymbolListener(listener); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderState.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderState.java new file mode 100644 index 000000000..b673531c7 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderState.java @@ -0,0 +1,1240 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.channel.state.ChangeChannelTimeoutEvent; +import io.github.dsheirer.channel.state.DecoderStateEvent; +import io.github.dsheirer.channel.state.DecoderStateEvent.Event; +import io.github.dsheirer.channel.state.State; +import io.github.dsheirer.channel.state.TimeslotDecoderState; +import io.github.dsheirer.controller.channel.Channel; +import io.github.dsheirer.controller.channel.Channel.ChannelType; +import io.github.dsheirer.controller.channel.ChannelEvent; +import io.github.dsheirer.controller.channel.IChannelEventListener; +import io.github.dsheirer.identifier.Form; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.IdentifierClass; +import io.github.dsheirer.identifier.IdentifierUpdateListener; +import io.github.dsheirer.identifier.MutableIdentifierCollection; +import io.github.dsheirer.identifier.Role; +import io.github.dsheirer.identifier.encryption.EncryptionKey; +import io.github.dsheirer.identifier.patch.PatchGroupManager; +import io.github.dsheirer.message.IMessage; +import io.github.dsheirer.module.decode.DecoderType; +import io.github.dsheirer.module.decode.event.DecodeEvent; +import io.github.dsheirer.module.decode.event.DecodeEventType; +import io.github.dsheirer.module.decode.p25.P25DecodeEvent; +import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; +import io.github.dsheirer.module.decode.p25.phase2.message.EncryptionSynchronizationSequence; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacMessage; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacPduType; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.AcknowledgeResponse; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.CallAlertExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.DenyResponse; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.EndPushToTalk; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.ExtendedFunctionCommand; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.ExtendedFunctionCommandExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupAffiliationQueryExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelGrantAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelGrantUpdateExplicit; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelGrantUpdateMultiple; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelGrantUpdateMultipleExplicit; +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.GroupVoiceServiceRequest; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.IndividualPagingMessage; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.MacRelease; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.MessageUpdateAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.MessageUpdateExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.PowerControlSignalQuality; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.PushToTalk; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.QueuedResponse; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.RadioUnitMonitorCommand; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.RadioUnitMonitorCommandEnhanced; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.RadioUnitMonitorCommandExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.SNDCPDataChannelGrant; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.SNDCPDataPageRequest; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.StatusQueryAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.StatusUpdateAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.StatusUpdateExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.TelephoneInterconnectAnswerRequest; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.TelephoneInterconnectVoiceChannelUser; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitAnswerRequestAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitAnswerRequestExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitVoiceChannelGrantAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitVoiceChannelGrantUpdateExtended; +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.sample.Listener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Decoder state for an APCO25 Phase II channel. Maintains the call/data/idle state of the channel and produces events + * by monitoring the decoded message stream. + * + */ +public class P25P2DecoderState extends TimeslotDecoderState implements IChannelEventListener, IdentifierUpdateListener +{ + private final static Logger mLog = LoggerFactory.getLogger(P25P2DecoderState.class); + + private ChannelType mChannelType; + private PatchGroupManager mPatchGroupManager = new PatchGroupManager(); + private P25P2NetworkConfigurationMonitor mNetworkConfigurationMonitor = new P25P2NetworkConfigurationMonitor(); + private Listener mChannelEventListener; + private DecodeEvent mCurrentCallEvent; + + /** + * Constructs an APCO-25 decoder state for a traffic channel. + * @param channel with configuration details + */ + public P25P2DecoderState(Channel channel, int timeslot) + { + super(timeslot); + mChannelType = channel.getChannelType(); + } + + /** + * Identifies the decoder type + */ + @Override + public DecoderType getDecoderType() + { + return DecoderType.P25_PHASE2; + } + + /** + * Implements the IChannelEventListener interface to receive traffic channel teardown notifications so that the + * traffic channel manager can manage traffic channel allocations. + */ + @Override + public Listener getChannelEventListener() + { + return mChannelEventListener; + } + + /** + * Performs a full reset to prepare this object for reuse on a new channel + */ + @Override + public void reset() + { + super.reset(); + resetState(); + } + +/** + * Resets any temporal state details + */ + protected void resetState() + { + super.resetState(); + closeCurrentCallEvent(System.currentTimeMillis(), true); + } + + /** + * Primary message processing method. + */ + @Override + public void receive(IMessage message) + { + if(message.isValid() && message.getTimeslot() == getTimeslot()) + { + if(message instanceof MacMessage) + { + processMacMessage((MacMessage)message); + } + else if(message instanceof AbstractVoiceTimeslot) + { + if(isEncrypted()) + { + broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.ENCRYPTED, getTimeslot())); + } + else + { + broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL, getTimeslot())); + } + + updateCurrentCall(null, null, message.getTimestamp()); + } + else if(message instanceof EncryptionSynchronizationSequence) + { + getIdentifierCollection().update(message.getIdentifiers()); + } + } + } + + /** + * Adds the current channel to the local identifier collection which will cause it to be broadcast to all of the + * other listeners and will allow both timeslots on this channel to receive it and update accordingly. + * + * @param channel to broadcast + */ + private void broadcastCurrentChannel(APCO25Channel channel) + { + getIdentifierCollection().update(channel); + } + + private void processMacMessage(MacMessage message) + { + mNetworkConfigurationMonitor.processMacMessage(message); + + MacStructure mac = message.getMacStructure(); + + switch((mac.getOpcode())) + { + case PUSH_TO_TALK: + for(Identifier identifier : mac.getIdentifiers()) + { + //Add to the identifier collection after filtering through the patch group manager + getIdentifierCollection().update(mPatchGroupManager.update(identifier)); + } + + PushToTalk ptt = (PushToTalk)mac; + + if(ptt.isEncrypted()) + { + updateCurrentCall(DecodeEventType.CALL_ENCRYPTED, ptt.getEncryptionKey().toString(), message.getTimestamp()); + } + else + { + updateCurrentCall(DecodeEventType.CALL, null, message.getTimestamp()); + } + break; + case END_PUSH_TO_TALK: + if(mac instanceof EndPushToTalk) + { + //Add the set of identifiers before we close out the call event to ensure they're captured in + //the closing event. + for(Identifier identifier : mac.getIdentifiers()) + { + //Add to the identifier collection after filtering through the patch group manager + getIdentifierCollection().update(mPatchGroupManager.update(identifier)); + } + + closeCurrentCallEvent(message.getTimestamp(), false); + getIdentifierCollection().remove(IdentifierClass.USER); + } + break; + case TDMA_0_NULL_INFORMATION_MESSAGE: + closeCurrentCallEvent(message.getTimestamp(), true); + continueState(State.ACTIVE); + break; + case TDMA_1_GROUP_VOICE_CHANNEL_USER_ABBREVIATED: + if(message.getMacPduType() == MacPduType.MAC_6_HANGTIME) + { + closeCurrentCallEvent(message.getTimestamp(), false); + getIdentifierCollection().remove(Role.FROM); + + for(Identifier identifier : mac.getIdentifiers()) + { + if(!(identifier.getForm() == Form.TALKGROUP && identifier.getRole() == Role.FROM)) + { + //Add to the identifier collection after filtering through the patch group manager + getIdentifierCollection().update(mPatchGroupManager.update(identifier)); + } + } + } + else + { + for(Identifier identifier : mac.getIdentifiers()) + { + //Add to the identifier collection after filtering through the patch group manager + getIdentifierCollection().update(mPatchGroupManager.update(identifier)); + } + + if(mac instanceof GroupVoiceChannelUserAbbreviated) + { + GroupVoiceChannelUserAbbreviated gvcua = (GroupVoiceChannelUserAbbreviated)mac; + + if(gvcua.getServiceOptions().isEncrypted()) + { + updateCurrentCall(DecodeEventType.CALL_GROUP_ENCRYPTED, null, message.getTimestamp()); + } + else + { + updateCurrentCall(DecodeEventType.CALL_GROUP, null, message.getTimestamp()); + } + } + } + break; + case TDMA_33_GROUP_VOICE_CHANNEL_USER_EXTENDED: + if(message.getMacPduType() == MacPduType.MAC_6_HANGTIME) + { + closeCurrentCallEvent(message.getTimestamp(), false); + getIdentifierCollection().remove(Role.FROM); + + for(Identifier identifier : mac.getIdentifiers()) + { + if(!(identifier.getForm() == Form.TALKGROUP && identifier.getRole() == Role.FROM)) + { + //Add to the identifier collection after filtering through the patch group manager + getIdentifierCollection().update(mPatchGroupManager.update(identifier)); + } + } + } + else + { + for(Identifier identifier : mac.getIdentifiers()) + { + //Add to the identifier collection after filtering through the patch group manager + getIdentifierCollection().update(mPatchGroupManager.update(identifier)); + } + + if(mac instanceof GroupVoiceChannelUserExtended) + { + GroupVoiceChannelUserExtended gvcue = (GroupVoiceChannelUserExtended)mac; + + if(gvcue.getServiceOptions().isEncrypted()) + { + updateCurrentCall(DecodeEventType.CALL_GROUP_ENCRYPTED, null, message.getTimestamp()); + } + else + { + updateCurrentCall(DecodeEventType.CALL_GROUP, null, message.getTimestamp()); + } + } + } + break; + case TDMA_2_UNIT_TO_UNIT_VOICE_CHANNEL_USER: + if(message.getMacPduType() == MacPduType.MAC_6_HANGTIME) + { + closeCurrentCallEvent(message.getTimestamp(), false); + getIdentifierCollection().remove(Role.FROM); + + for(Identifier identifier : mac.getIdentifiers()) + { + if(!(identifier.getForm() == Form.TALKGROUP && identifier.getRole() == Role.FROM)) + { + //Add to the identifier collection after filtering through the patch group manager + getIdentifierCollection().update(mPatchGroupManager.update(identifier)); + } + } + } + else + { + for(Identifier identifier : mac.getIdentifiers()) + { + //Add to the identifier collection after filtering through the patch group manager + getIdentifierCollection().update(mPatchGroupManager.update(identifier)); + } + + if(mac instanceof UnitToUnitVoiceChannelUserAbbreviated) + { + UnitToUnitVoiceChannelUserAbbreviated uuvcua = (UnitToUnitVoiceChannelUserAbbreviated)mac; + + if(uuvcua.getServiceOptions().isEncrypted()) + { + updateCurrentCall(DecodeEventType.CALL_UNIT_TO_UNIT_ENCRYPTED, null, message.getTimestamp()); + } + else + { + updateCurrentCall(DecodeEventType.CALL_UNIT_TO_UNIT, null, message.getTimestamp()); + } + } + } + break; + case TDMA_34_UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED: + if(message.getMacPduType() == MacPduType.MAC_6_HANGTIME) + { + closeCurrentCallEvent(message.getTimestamp(), false); + getIdentifierCollection().remove(Role.FROM); + + for(Identifier identifier : mac.getIdentifiers()) + { + if(!(identifier.getForm() == Form.TALKGROUP && identifier.getRole() == Role.FROM)) + { + //Add to the identifier collection after filtering through the patch group manager + getIdentifierCollection().update(mPatchGroupManager.update(identifier)); + } + } + } + else + { + for(Identifier identifier : mac.getIdentifiers()) + { + //Add to the identifier collection after filtering through the patch group manager + getIdentifierCollection().update(mPatchGroupManager.update(identifier)); + } + + if(mac instanceof UnitToUnitVoiceChannelUserExtended) + { + UnitToUnitVoiceChannelUserExtended uuvcue = (UnitToUnitVoiceChannelUserExtended)mac; + + if(uuvcue.getServiceOptions().isEncrypted()) + { + updateCurrentCall(DecodeEventType.CALL_UNIT_TO_UNIT_ENCRYPTED, null, message.getTimestamp()); + } + else + { + updateCurrentCall(DecodeEventType.CALL_UNIT_TO_UNIT, null, message.getTimestamp()); + } + } + } + break; + case TDMA_3_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER: + if(message.getMacPduType() == MacPduType.MAC_6_HANGTIME) + { + closeCurrentCallEvent(message.getTimestamp(), false); + getIdentifierCollection().remove(Role.FROM); + + for(Identifier identifier : mac.getIdentifiers()) + { + if(!(identifier.getForm() == Form.TALKGROUP && identifier.getRole() == Role.FROM)) + { + //Add to the identifier collection after filtering through the patch group manager + getIdentifierCollection().update(mPatchGroupManager.update(identifier)); + } + } + } + else + { + for(Identifier identifier : mac.getIdentifiers()) + { + //Add to the identifier collection after filtering through the patch group manager + getIdentifierCollection().update(mPatchGroupManager.update(identifier)); + } + + if(mac instanceof TelephoneInterconnectVoiceChannelUser) + { + TelephoneInterconnectVoiceChannelUser tivcu = (TelephoneInterconnectVoiceChannelUser)mac; + + if(tivcu.getServiceOptions().isEncrypted()) + { + updateCurrentCall(DecodeEventType.CALL_INTERCONNECT_ENCRYPTED, null, message.getTimestamp()); + } + else + { + updateCurrentCall(DecodeEventType.CALL_INTERCONNECT, null, message.getTimestamp()); + } + } + } + continueState(State.ACTIVE); + break; + case TDMA_5_GROUP_VOICE_CHANNEL_GRANT_UPDATE_MULTIPLE: + if(getCurrentChannel() == null && mac instanceof GroupVoiceChannelGrantUpdateMultiple) + { + GroupVoiceChannelGrantUpdateMultiple gvcgum = (GroupVoiceChannelGrantUpdateMultiple)mac; + + if(isCurrentGroup(gvcgum.getGroupAddressA())) + { + broadcastCurrentChannel(gvcgum.getChannelA()); + } + + if(getCurrentChannel() == null && gvcgum.hasGroupB() && isCurrentGroup(gvcgum.getGroupAddressB())) + { + broadcastCurrentChannel(gvcgum.getChannelB()); + } + + if(getCurrentChannel() == null && gvcgum.hasGroupC() && isCurrentGroup(gvcgum.getGroupAddressC())) + { + broadcastCurrentChannel(gvcgum.getChannelC()); + } + } + continueState(State.ACTIVE); + break; + case TDMA_37_GROUP_VOICE_CHANNEL_GRANT_UPDATE_MULTIPLE_EXPLICIT: + if(getCurrentChannel() == null && mac instanceof GroupVoiceChannelGrantUpdateMultipleExplicit) + { + GroupVoiceChannelGrantUpdateMultipleExplicit gvcgume = (GroupVoiceChannelGrantUpdateMultipleExplicit)mac; + + if(isCurrentGroup(gvcgume.getGroupAddressA())) + { + broadcastCurrentChannel(gvcgume.getChannelA()); + } + + if(getCurrentChannel() == null && isCurrentGroup(gvcgume.getGroupAddressB())) + { + broadcastCurrentChannel(gvcgume.getChannelB()); + } + } + continueState(State.ACTIVE); + break; + case PHASE1_64_GROUP_VOICE_CHANNEL_GRANT_ABBREVIATED: + if(getCurrentChannel() == null && mac instanceof GroupVoiceChannelGrantAbbreviated) + { + GroupVoiceChannelGrantAbbreviated gvcga = (GroupVoiceChannelGrantAbbreviated)mac; + + if(isCurrentGroup(gvcga.getGroupAddress())) + { + broadcastCurrentChannel(gvcga.getChannel()); + } + } + continueState(State.ACTIVE); + break; + case PHASE1_66_GROUP_VOICE_CHANNEL_GRANT_UPDATE: + if(getCurrentChannel() == null && mac instanceof GroupVoiceChannelGrantUpdate) + { + GroupVoiceChannelGrantUpdate gvcgu = (GroupVoiceChannelGrantUpdate)mac; + + if(isCurrentGroup(gvcgu.getGroupAddressA())) + { + broadcastCurrentChannel(gvcgu.getChannelA()); + } + + if(getCurrentChannel() == null && isCurrentGroup(gvcgu.getGroupAddressB())) + { + broadcastCurrentChannel(gvcgu.getChannelB()); + } + } + continueState(State.ACTIVE); + break; + case PHASE1_70_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_ABBREVIATED: + if(getCurrentChannel() == null && mac instanceof UnitToUnitVoiceChannelGrantAbbreviated) + { + UnitToUnitVoiceChannelGrantAbbreviated uuvcga = (UnitToUnitVoiceChannelGrantAbbreviated)mac; + + if(isCurrentGroup(uuvcga.getSourceAddress()) || isCurrentGroup(uuvcga.getTargetAddress())) + { + broadcastCurrentChannel(uuvcga.getChannel()); + } + } + continueState(State.ACTIVE); + break; + case PHASE1_195_GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT: + if(getCurrentChannel() == null && mac instanceof GroupVoiceChannelGrantUpdateExplicit) + { + GroupVoiceChannelGrantUpdateExplicit gvcgue = (GroupVoiceChannelGrantUpdateExplicit)mac; + + if(isCurrentGroup(gvcgue.getGroupAddress())) + { + broadcastCurrentChannel(gvcgue.getChannel()); + } + } + continueState(State.ACTIVE); + break; + case PHASE1_198_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_EXTENDED: + if(getCurrentChannel() == null && mac instanceof UnitToUnitVoiceChannelGrantUpdateExtended) + { + UnitToUnitVoiceChannelGrantUpdateExtended uuvcgue = (UnitToUnitVoiceChannelGrantUpdateExtended)mac; + + if(isCurrentGroup(uuvcgue.getTargetAddress())) + { + broadcastCurrentChannel(uuvcgue.getChannel()); + } + } + continueState(State.ACTIVE); + break; + case TDMA_17_INDIRECT_GROUP_PAGING: + MutableIdentifierCollection icGroupPaging = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icGroupPaging.remove(IdentifierClass.USER); + icGroupPaging.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.PAGE.toString()) + .details("GROUP PAGE") + .identifiers(icGroupPaging) + .build()); + continueState(State.ACTIVE); + break; + case TDMA_18_INDIVIDUAL_PAGING_MESSAGE_WITH_PRIORITY: + if(mac instanceof IndividualPagingMessage) + { + IndividualPagingMessage ipm = (IndividualPagingMessage)mac; + MutableIdentifierCollection icIndividualPaging = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icIndividualPaging.remove(IdentifierClass.USER); + icIndividualPaging.update(mac.getIdentifiers()); + boolean priority = ipm.isTalkgroupPriority1() || ipm.isTalkgroupPriority2() || + ipm.isTalkgroupPriority3() || ipm.isTalkgroupPriority4(); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.PAGE.toString()) + .details((priority ? "PRIORITY " : "") + "USER PAGE") + .identifiers(icIndividualPaging) + .build()); + } + continueState(State.ACTIVE); + break; + case TDMA_48_POWER_CONTROL_SIGNAL_QUALITY: + if(mac instanceof PowerControlSignalQuality) + { + PowerControlSignalQuality pcsq = (PowerControlSignalQuality)mac; + + MutableIdentifierCollection icPowerControl = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icPowerControl.remove(IdentifierClass.USER); + icPowerControl.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.COMMAND.toString()) + .details("ADJUST TRANSMIT POWER - RF:" + pcsq.getRFLevel() + " BER:" + pcsq.getBitErrorRate()) + .identifiers(icPowerControl) + .build()); + } + continueState(State.ACTIVE); + break; + case TDMA_49_MAC_RELEASE: + if(mac instanceof MacRelease) + { + MacRelease mr = (MacRelease)mac; + + MutableIdentifierCollection icMacRelease = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icMacRelease.remove(IdentifierClass.USER); + icMacRelease.update(mac.getIdentifiers()); + + closeCurrentCallEvent(message.getTimestamp(), true); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.COMMAND.toString()) + .details((mr.isForcedPreemption() ? "FORCED " : "") + "CALL PREEMPTION" + (mr.isTalkerPreemption() ? " BY USER" : "")) + .identifiers(icMacRelease) + .build()); + } + break; + case PHASE1_65_GROUP_VOICE_SERVICE_REQUEST: + if(mac instanceof GroupVoiceServiceRequest) + { + GroupVoiceServiceRequest gvsr = (GroupVoiceServiceRequest)mac; + + MutableIdentifierCollection icMacRelease = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icMacRelease.remove(IdentifierClass.USER); + icMacRelease.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.REQUEST.toString()) + .details("GROUP VOICE SERVICE " + gvsr.getServiceOptions()) + .identifiers(icMacRelease) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_68_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_ABBREVIATED: + if(mac instanceof UnitToUnitVoiceChannelGrantAbbreviated) + { + UnitToUnitVoiceChannelGrantAbbreviated uuvcga = (UnitToUnitVoiceChannelGrantAbbreviated)mac; + MutableIdentifierCollection icGrant = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icGrant.remove(IdentifierClass.USER); + icGrant.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(uuvcga.getChannel()) + .eventDescription(DecodeEventType.CALL_UNIT_TO_UNIT.toString()) + .details("VOICE CHANNEL GRANT") + .identifiers(icGrant) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_69_UNIT_TO_UNIT_ANSWER_REQUEST_ABBREVIATED: + if(mac instanceof UnitToUnitAnswerRequestAbbreviated) + { + UnitToUnitAnswerRequestAbbreviated uuara = (UnitToUnitAnswerRequestAbbreviated)mac; + MutableIdentifierCollection icRequest = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icRequest.remove(IdentifierClass.USER); + icRequest.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.REQUEST.toString()) + .details("UNIT-TO-UNIT ANSWER REQUEST - " + uuara.getServiceOptions()) + .identifiers(icRequest) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_74_TELEPHONE_INTERCONNECT_ANSWER_REQUEST: + if(mac instanceof TelephoneInterconnectAnswerRequest) + { + TelephoneInterconnectAnswerRequest tiar = (TelephoneInterconnectAnswerRequest)mac; + MutableIdentifierCollection icRequest = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icRequest.remove(IdentifierClass.USER); + icRequest.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.REQUEST.toString()) + .details("TELEPHONE INTERCONNECT ANSWER REQUEST") + .identifiers(icRequest) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_76_RADIO_UNIT_MONITOR_COMMAND_ABBREVIATED: + if(mac instanceof RadioUnitMonitorCommand) + { + RadioUnitMonitorCommand rumc = (RadioUnitMonitorCommand)mac; + MutableIdentifierCollection icRequest = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icRequest.remove(IdentifierClass.USER); + icRequest.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.COMMAND.toString()) + .details("RADIO UNIT MONITOR" + (rumc.isSilentMonitor() ? " (STEALTH)" : "") + + " TIME:" + rumc.getTransmitTime() + " MULTIPLIER:" + rumc.getTransmitMultiplier()) + .identifiers(icRequest) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_84_SNDCP_DATA_CHANNEL_GRANT: + if(mac instanceof SNDCPDataChannelGrant) + { + SNDCPDataChannelGrant sdcg = (SNDCPDataChannelGrant)mac; + MutableIdentifierCollection icGrant = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icGrant.remove(IdentifierClass.USER); + icGrant.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(sdcg.getChannel()) + .eventDescription(sdcg.getServiceOptions().isEncrypted() ? DecodeEventType.DATA_CALL_ENCRYPTED.toString() : DecodeEventType.DATA_CALL.toString()) + .details("SNDCP CHANNEL GRANT " + sdcg.getServiceOptions()) + .identifiers(icGrant) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_85_SNDCP_DATA_PAGE_REQUEST: + if(mac instanceof SNDCPDataPageRequest) + { + SNDCPDataPageRequest sdpr = (SNDCPDataPageRequest)mac; + MutableIdentifierCollection icPage = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icPage.remove(IdentifierClass.USER); + icPage.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.PAGE.toString()) + .details("SNDCP DATA PAGE " + sdpr.getServiceOptions()) + .identifiers(icPage) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_88_STATUS_UPDATE_ABBREVIATED: + if(mac instanceof StatusUpdateAbbreviated) + { + StatusUpdateAbbreviated sua = (StatusUpdateAbbreviated)mac; + MutableIdentifierCollection icStatusUpdate = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icStatusUpdate.remove(IdentifierClass.USER); + icStatusUpdate.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.STATUS.toString()) + .details("STATUS UPDATE - UNIT:" + sua.getUnitStatus() + " USER:" + sua.getUserStatus()) + .identifiers(icStatusUpdate) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_90_STATUS_QUERY_ABBREVIATED: + if(mac instanceof StatusQueryAbbreviated) + { + MutableIdentifierCollection icStatusUpdate = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icStatusUpdate.remove(IdentifierClass.USER); + icStatusUpdate.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.STATUS.toString()) + .details("STATUS QUERY") + .identifiers(icStatusUpdate) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_92_MESSAGE_UPDATE_ABBREVIATED: + if(mac instanceof MessageUpdateAbbreviated) + { + MessageUpdateAbbreviated mua = (MessageUpdateAbbreviated)mac; + MutableIdentifierCollection icStatusUpdate = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icStatusUpdate.remove(IdentifierClass.USER); + icStatusUpdate.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.SDM.toString()) + .details("MESSAGE UPDATE - " + mua.getShortDataMessage()) + .identifiers(icStatusUpdate) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_94_RADIO_UNIT_MONITOR_COMMAND_ENHANCED: + if(mac instanceof RadioUnitMonitorCommandEnhanced) + { + RadioUnitMonitorCommandEnhanced rumc = (RadioUnitMonitorCommandEnhanced)mac; + MutableIdentifierCollection icRequest = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icRequest.remove(IdentifierClass.USER); + icRequest.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.COMMAND.toString()) + .details("RADIO UNIT MONITOR" + (rumc.isStealthMode() ? " (STEALTH)" : "") + + " ENCRYPTION:" + rumc.getEncryption() + + " TIME:" + rumc.getTransmitTime()) + .identifiers(icRequest) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_95_CALL_ALERT_ABBREVIATED: + MutableIdentifierCollection icCallAlert = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icCallAlert.remove(IdentifierClass.USER); + icCallAlert.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.CALL_ALERT.toString()) + .identifiers(icCallAlert) + .build()); + continueState(State.ACTIVE); + break; + case PHASE1_96_ACK_RESPONSE: + if(mac instanceof AcknowledgeResponse) + { + AcknowledgeResponse ar = (AcknowledgeResponse)mac; + MutableIdentifierCollection icAckResponse = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icAckResponse.remove(IdentifierClass.USER); + icAckResponse.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.RESPONSE.toString()) + .details("ACKNOWLEDGE: " + ar.getServiceType()) + .identifiers(icAckResponse) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_97_QUEUED_RESPONSE: + if(mac instanceof QueuedResponse) + { + QueuedResponse qr = (QueuedResponse)mac; + + MutableIdentifierCollection icQueuedResponse = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icQueuedResponse.remove(IdentifierClass.USER); + icQueuedResponse.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.RESPONSE.toString()) + .details("QUEUED - " + qr.getQueuedResponseServiceType() + + " REASON:" + qr.getQueuedResponseReason() + " ADDL:" + qr.getAdditionalInfo()) + .identifiers(icQueuedResponse) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_100_EXTENDED_FUNCTION_COMMAND_ABBREVIATED: + if(mac instanceof ExtendedFunctionCommand) + { + ExtendedFunctionCommand efc = (ExtendedFunctionCommand)mac; + + MutableIdentifierCollection icExtendedFunction = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icExtendedFunction.remove(IdentifierClass.USER); + icExtendedFunction.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.COMMAND.toString()) + .details("EXTENDED FUNCTION: " + efc.getExtendedFunction() + " ARGUMENTS:" + efc.getArguments()) + .identifiers(icExtendedFunction) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_103_DENY_RESPONSE: + if(mac instanceof DenyResponse) + { + DenyResponse dr = (DenyResponse)mac; + MutableIdentifierCollection icDenyResponse = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icDenyResponse.remove(IdentifierClass.USER); + icDenyResponse.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.RESPONSE.toString()) + .details("DENY: " + dr.getDeniedServiceType() + " REASON:" + dr.getDenyReason() + " ADDL:" + dr.getAdditionalInfo()) + .identifiers(icDenyResponse) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_106_GROUP_AFFILIATION_QUERY_ABBREVIATED: + MutableIdentifierCollection icGroupAffiliationQuery = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icGroupAffiliationQuery.remove(IdentifierClass.USER); + icGroupAffiliationQuery.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.QUERY.toString()) + .details("GROUP AFFILIATION") + .identifiers(icGroupAffiliationQuery) + .build()); + continueState(State.ACTIVE); + break; + case PHASE1_109_UNIT_REGISTRATION_COMMAND_ABBREVIATED: + MutableIdentifierCollection icUnitRegisterCommand = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icUnitRegisterCommand.remove(IdentifierClass.USER); + icUnitRegisterCommand.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.COMMAND.toString()) + .details("UNIT REGISTRATION") + .identifiers(icUnitRegisterCommand) + .build()); + continueState(State.ACTIVE); + break; + case PHASE1_197_UNIT_TO_UNIT_ANSWER_REQUEST_EXTENDED: + if(mac instanceof UnitToUnitAnswerRequestExtended) + { + UnitToUnitAnswerRequestExtended uuare = (UnitToUnitAnswerRequestExtended)mac; + + MutableIdentifierCollection icUnitAnswerRequestExtended = + new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icUnitAnswerRequestExtended.remove(IdentifierClass.USER); + icUnitAnswerRequestExtended.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.REQUEST.toString()) + .details("UNIT-TO-UNIT ANSWER REQUEST " + uuare.getServiceOptions()) + .identifiers(icUnitAnswerRequestExtended) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_204_RADIO_UNIT_MONITOR_COMMAND_EXTENDED: + if(mac instanceof RadioUnitMonitorCommandExtended) + { + RadioUnitMonitorCommandExtended rumce = (RadioUnitMonitorCommandExtended)mac; + MutableIdentifierCollection icRequest = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icRequest.remove(IdentifierClass.USER); + icRequest.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.COMMAND.toString()) + .details("RADIO UNIT MONITOR" + (rumce.isSilentMonitor() ? " (STEALTH)" : "") + + " TIME:" + rumce.getTransmitTime() + "MULTIPLIER:" + rumce.getTransmitMultiplier()) + .identifiers(icRequest) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_216_STATUS_UPDATE_EXTENDED: + if(mac instanceof StatusUpdateExtended) + { + StatusUpdateExtended sue = (StatusUpdateExtended)mac; + MutableIdentifierCollection icStatusUpdate = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icStatusUpdate.remove(IdentifierClass.USER); + icStatusUpdate.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.STATUS.toString()) + .details("STATUS UPDATE - UNIT:" + sue.getUnitStatus() + " USER:" + sue.getUserStatus()) + .identifiers(icStatusUpdate) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_218_STATUS_QUERY_EXTENDED: + MutableIdentifierCollection icStatusQueryExtended = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icStatusQueryExtended.remove(IdentifierClass.USER); + icStatusQueryExtended.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.STATUS.toString()) + .details("STATUS QUERY") + .identifiers(icStatusQueryExtended) + .build()); + continueState(State.ACTIVE); + break; + case PHASE1_220_MESSAGE_UPDATE_EXTENDED: + if(mac instanceof MessageUpdateExtended) + { + MessageUpdateExtended mue = (MessageUpdateExtended)mac; + MutableIdentifierCollection icStatusUpdate = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icStatusUpdate.remove(IdentifierClass.USER); + icStatusUpdate.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.SDM.toString()) + .details("MESSAGE UPDATE - " + mue.getShortDataMessage()) + .identifiers(icStatusUpdate) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_223_CALL_ALERT_EXTENDED: + if(mac instanceof CallAlertExtended) + { + MutableIdentifierCollection icCallAlertExtended = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icCallAlertExtended.remove(IdentifierClass.USER); + icCallAlertExtended.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.CALL_ALERT.toString()) + .identifiers(icCallAlertExtended) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_228_EXTENDED_FUNCTION_COMMAND_EXTENDED: + if(mac instanceof ExtendedFunctionCommandExtended) + { + ExtendedFunctionCommandExtended efce = (ExtendedFunctionCommandExtended)mac; + + MutableIdentifierCollection icExtendedFunction = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icExtendedFunction.remove(IdentifierClass.USER); + icExtendedFunction.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.COMMAND.toString()) + .details("EXTENDED FUNCTION: " + efce.getExtendedFunction() + " ARGUMENTS:" + efce.getArguments()) + .identifiers(icExtendedFunction) + .build()); + } + continueState(State.ACTIVE); + break; + case PHASE1_234_GROUP_AFFILIATION_QUERY_EXTENDED: + if(mac instanceof GroupAffiliationQueryExtended) + { + MutableIdentifierCollection icGroupAffiliationQueryExtended = + new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); + icGroupAffiliationQueryExtended.remove(IdentifierClass.USER); + icGroupAffiliationQueryExtended.update(mac.getIdentifiers()); + + broadcast(P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.QUERY.toString()) + .details("GROUP AFFILIATION") + .identifiers(icGroupAffiliationQueryExtended) + .build()); + } + continueState(State.ACTIVE); + break; + + case PHASE1_115_IDENTIFIER_UPDATE_TDMA: + case PHASE1_116_IDENTIFIER_UPDATE_V_UHF: + case PHASE1_117_TIME_AND_DATE_ANNOUNCEMENT: + case PHASE1_120_SYSTEM_SERVICE_BROADCAST: + case PHASE1_121_SECONDARY_CONTROL_CHANNEL_BROADCAST_ABBREVIATED: + case PHASE1_122_RFSS_STATUS_BROADCAST_ABBREVIATED: + case PHASE1_123_NETWORK_STATUS_BROADCAST_ABBREVIATED: + case PHASE1_124_ADJACENT_STATUS_BROADCAST_ABBREVIATED: + case PHASE1_125_IDENTIFIER_UPDATE: + case PHASE1_PARTITION_1_UNKNOWN_OPCODE: + case VENDOR_PARTITION_2_UNKNOWN_OPCODE: + case PHASE1_214_SNDCP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT: + case PHASE1_233_SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT: + case PHASE1_250_RFSS_STATUS_BROADCAST_EXTENDED: + case PHASE1_251_NETWORK_STATUS_BROADCAST_EXTENDED: + case PHASE1_252_ADJACENT_STATUS_BROADCAST_EXTENDED: + case PHASE1_EXTENDED_PARTITION_3_UNKNOWN_OPCODE: + case TDMA_PARTITION_0_UNKNOWN_OPCODE: + case OBSOLETE_PHASE1_93_RADIO_UNIT_MONITOR_COMMAND: + case PHASE1_192_GROUP_VOICE_CHANNEL_GRANT_EXTENDED: + case PHASE1_196_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_EXTENDED: + case UNKNOWN: + default: + continueState(State.ACTIVE); + //ignore + break; + } + } + + /** + * Indicates if the identifier argument matches the current (TO) talkgroup for this channel and timeslot + * @param identifier to match + * @return true if the identifier matches the current channel's TO talkgroup + */ + private boolean isCurrentGroup(Identifier identifier) + { + if(identifier != null) + { + for(Identifier id: getIdentifierCollection().getIdentifiers(Role.TO)) + { + if(identifier.equals(id)) + { + return true; + } + } + } + + return false; + } + + /** + * Broadcasts a state continuation. If we're currently in a call, then we broadcast a call continuation, otherwise + * we broadcast a continuation of the specified state. + * @param state to continue + */ + private void continueState(State state) + { + if(mCurrentCallEvent != null) + { + broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL, getTimeslot())); + } + else + { + broadcast(new DecoderStateEvent(this, Event.DECODE, state, getTimeslot())); + } + } + + + /** + * Updates or creates a current call event. + * + * @param type of call that will be used as an event description + * @param details of the call (optional) + * @param timestamp of the message indicating a call or continuation + */ + private void updateCurrentCall(DecodeEventType type, String details, long timestamp) + { + if(mCurrentCallEvent == null) + { + mCurrentCallEvent = P25DecodeEvent.builder(timestamp) + .channel(getCurrentChannel()) + .eventDescription(type != null ? type.toString() : DecodeEventType.CALL.toString()) + .details(details) + .identifiers(getIdentifierCollection().copyOf()) + .build(); + + broadcast(mCurrentCallEvent); + broadcast(new DecoderStateEvent(this, Event.START, State.CALL, getTimeslot())); + } + else + { + if(type != null) + { + mCurrentCallEvent.setEventDescription(type.toString()); + } + + if(details != null) + { + mCurrentCallEvent.setDetails(details); + } + + mCurrentCallEvent.setIdentifierCollection(getIdentifierCollection().copyOf()); + mCurrentCallEvent.end(timestamp); + broadcast(mCurrentCallEvent); + broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL, getTimeslot())); + } + } + + /** + * Ends/closes the current call event. + * + * @param timestamp of the message that indicates the event has ended. + */ + private void closeCurrentCallEvent(long timestamp, boolean resetIdentifiers) + { + if(mCurrentCallEvent != null) + { + mCurrentCallEvent.end(timestamp); + broadcast(mCurrentCallEvent); + mCurrentCallEvent = null; + + broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.ACTIVE, getTimeslot())); + } + else + { + continueState(State.ACTIVE); + } + + if(resetIdentifiers) + { + getIdentifierCollection().remove(IdentifierClass.USER); + } + else + { + //Only clear the from identifier at this point ... the channel may still be allocated to the TO talkgroup + getIdentifierCollection().remove(IdentifierClass.USER, Role.FROM); + } + } + + /** + * Indicates if the current set of identifiers contains an encryption key indicating that the communication is + * encrypted. + * + * @return true if there is an encryption key indicating encryption is currently in use. + */ + private boolean isEncrypted() + { + for(Identifier identifier : getIdentifierCollection().getIdentifiers(Form.ENCRYPTION_KEY)) + { + if(identifier.getValue() instanceof EncryptionKey && ((EncryptionKey)identifier.getValue()).isEncrypted()) + { + return true; + } + } + + return false; + } + + @Override + public String getActivitySummary() + { + return mNetworkConfigurationMonitor.getActivitySummary(); + } + + @Override + public void receiveDecoderStateEvent(DecoderStateEvent event) + { + switch(event.getEvent()) + { + case RESET: + resetState(); + mNetworkConfigurationMonitor.reset(); + break; + default: + break; + } + } + + @Override + public void start() + { + //Change the default (45-second) traffic channel timeout to 1 second + if(mChannelType == ChannelType.TRAFFIC) + { + broadcast(new ChangeChannelTimeoutEvent(this, ChannelType.TRAFFIC, 1000, getTimeslot())); + } + } + + @Override + public void init() + { + } + + @Override + public void stop() + { + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2MessageFramer.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2MessageFramer.java new file mode 100644 index 000000000..44e53d8ac --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2MessageFramer.java @@ -0,0 +1,281 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.alias.AliasModel; +import io.github.dsheirer.audio.AudioPacketManager; +import io.github.dsheirer.audio.playback.AudioPlaybackManager; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.controller.channel.Channel; +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.MessageInjectionModule; +import io.github.dsheirer.module.Module; +import io.github.dsheirer.module.ProcessingChain; +import io.github.dsheirer.module.decode.DecoderFactory; +import io.github.dsheirer.module.decode.DecoderType; +import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters; +import io.github.dsheirer.preference.UserPreferences; +import io.github.dsheirer.record.binary.BinaryReader; +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableByteBuffer; +import io.github.dsheirer.settings.SettingsManager; +import io.github.dsheirer.source.SourceManager; +import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +/** + * P25 Sync Detector and Message Framer. Includes capability to detect PLL out-of-phase lock errors + * and issue phase corrections. + */ +public class P25P2MessageFramer implements Listener +{ + private final static Logger mLog = LoggerFactory.getLogger(P25P2MessageFramer.class); + + private P25P2SuperFrameDetector mSuperFrameDetector; + private boolean mAssemblingMessage = false; + private CorrectedBinaryMessage mBinaryMessage; + private DataUnitID mDataUnitID; + private PDUSequence mPDUSequence; + private int[] mCorrectedNID; + private int mNAC; + private int mStatusSymbolDibitCounter = 0; + private int mTrailingDibitsToSuppress = 0; + private double mBitRate; + private long mCurrentTime = System.currentTimeMillis(); + private ISyncDetectListener mSyncDetectListener; + + public P25P2MessageFramer(IPhaseLockedLoop phaseLockedLoop, int bitRate) + { + mSuperFrameDetector = new P25P2SuperFrameDetector(phaseLockedLoop); + mBitRate = bitRate; + } + + public P25P2MessageFramer(int bitRate) + { + this(null, bitRate); + } + + /** + * Sets or updates the scramble parameters for the current channel + * @param scrambleParameters + */ + public void setScrambleParameters(ScrambleParameters scrambleParameters) + { + if(mSuperFrameDetector != null) + { + mSuperFrameDetector.setScrambleParameters(scrambleParameters); + } + } + + /** + * Sets the sample rate for the sync detector + */ + public void setSampleRate(double sampleRate) + { + mSuperFrameDetector.setSampleRate(sampleRate); + } + + /** + * Registers a sync detect listener to be notified each time a sync pattern and NID are detected. + */ + public void setSyncDetectListener(ISyncDetectListener syncDetectListener) + { + mSyncDetectListener = syncDetectListener; + } + + /** + * Current timestamp or timestamp of incoming message buffers that is continuously updated to as + * close as possible to the bits processed for the expected baud rate. + * + * @return + */ + private long getTimestamp() + { + return mCurrentTime; + } + + /** + * Sets the current time. This should be invoked by an incoming message buffer stream. + * + * @param currentTime + */ + public void setCurrentTime(long currentTime) + { + mCurrentTime = currentTime; + } + + /** + * Updates the current timestamp based on the number of bits processed versus the bit rate per second + * in order to keep an accurate running timestamp to use for timestamped message creation. + * + * @param bitsProcessed thus far + */ + private void updateBitsProcessed(int bitsProcessed) + { + if(bitsProcessed > 0) + { + mCurrentTime += (long)((double)bitsProcessed / mBitRate * 1000.0); + } + } + + /** + * Registers the listener for messages produced by this message framer + * + * @param messageListener to receive framed and decoded messages + */ + public void setListener(Listener messageListener) + { + mSuperFrameDetector.setListener(messageListener); + } + + public P25P2SuperFrameDetector getSuperFrameDetector() + { + return mSuperFrameDetector; + } + + /** + * Primary method for streaming decoded symbol dibits for message framing. + * + * @param dibit to process + */ + @Override + public void receive(Dibit dibit) + { + mSuperFrameDetector.receive(dibit); + } + + private void reset(int bitsProcessed) + { + updateBitsProcessed(bitsProcessed); + mPDUSequence = null; + mBinaryMessage = null; + mAssemblingMessage = false; + mDataUnitID = null; + mNAC = 0; + mSuperFrameDetector.reset(); + mStatusSymbolDibitCounter = 0; + } + + /** + * Primary method for streaming decoded symbol byte arrays. + * + * @param buffer to process into a stream of dibits for processing. + */ + public void receive(ReusableByteBuffer buffer) + { + //TODO: set timestamp in super frame detector + setCurrentTime(buffer.getTimestamp()); + + for(byte value : buffer.getBytes()) + { + for(int x = 0; x <= 3; x++) + { + receive(Dibit.parse(value, x)); + } + } + + buffer.decrementUserCount(); + } + + public static void main(String[] args) + { + UserPreferences userPreferences = new UserPreferences(); + AliasModel aliasModel = new AliasModel(); + SourceManager sourceManager = new SourceManager(null, new SettingsManager(new TunerConfigurationModel()), userPreferences); + AudioPlaybackManager audioPlaybackManager = new AudioPlaybackManager(sourceManager.getMixerManager()); + + //Audio packets are routed through the audio packet manager for metadata enrichment and then + //distributed to the audio packet processors (ie playback, recording, streaming, etc.) + AudioPacketManager audioPacketManager = new AudioPacketManager(aliasModel); + audioPacketManager.addListener(audioPlaybackManager); + audioPacketManager.start(); + + Channel channel = new Channel(); + DecodeConfigP25Phase2 decodeP2 = new DecodeConfigP25Phase2(); +// decodeP2.setScrambleParameters(new ScrambleParameters(1, 972, 972)); + decodeP2.setScrambleParameters(new ScrambleParameters(781824, 686, 677)); //CNYICC - Rome + channel.setDecodeConfiguration(decodeP2); + List modules = DecoderFactory.getModules(null, channel, aliasModel, userPreferences); + MessageInjectionModule messageInjectionModule = new MessageInjectionModule(); + modules.add(messageInjectionModule); + ProcessingChain processingChain = new ProcessingChain(channel, aliasModel); + processingChain.addAudioPacketListener(audioPacketManager); + processingChain.addModules(modules); + processingChain.start(); + + P25P2MessageFramer messageFramer = new P25P2MessageFramer(null, DecoderType.P25_PHASE1.getProtocol().getBitRate()); + messageFramer.setScrambleParameters(decodeP2.getScrambleParameters()); + P25P2MessageProcessor messageProcessor = new P25P2MessageProcessor(); +// P25P2CallSequenceRecorder frameRecorder = new P25P2CallSequenceRecorder(new UserPreferences(), 154250000); + messageFramer.setListener(messageProcessor); + messageProcessor.setMessageListener(new Listener() + { + @Override + public void receive(IMessage message) + { +// if(message.getTimeslot() == 0) +// { + mLog.debug(message.toString()); +// } + + messageInjectionModule.receive(message); +// frameRecorder.receive(message); + } + }); + + + + +// Path path = Paths.get("/media/denny/500G1EXT4/RadioRecordings/APCO25P2/DFW Airport Encrypted/20190321_192101_12000BPS_APCO25PHASE2_DFW_Irving_DFW_Phase_II_baseband_20181015_182924_good_phase_2.wav.bits"); +// Path path = Paths.get("/media/denny/500G1EXT4/RadioRecordings/APCO25P2/DFW Airport Encrypted/20190224_101332_12000BPS_APCO25PHASE2_DFWAirport_Site_857_3875_baseband_20181213_223136.bits"); +// Path path = Paths.get("/media/denny/500G1EXT4/RadioRecordings/APCO25P2/CNYICC/20190323_042605_12000BPS_APCO25PHASE2_CNYICC_ROME_154_250_1.bits"); +// Path path = Paths.get("/media/denny/500G1EXT4/RadioRecordings/APCO25P2/CNYICC/20190323_042806_12000BPS_APCO25PHASE2_CNYICC_ROME_154_250_3.bits"); +// Path path = Paths.get("/media/denny/500G1EXT4/RadioRecordings/APCO25P2/CNYICC/20190323_042830_12000BPS_APCO25PHASE2_CNYICC_ROME_154_250_4.bits"); +// Path path = Paths.get("/media/denny/500G1EXT4/RadioRecordings/APCO25P2/CNYICC/20190323_042853_12000BPS_APCO25PHASE2_CNYICC_ROME_154_250_5.bits"); + Path path = Paths.get("/media/denny/500G1EXT4/RadioRecordings/APCO25P2/CNYICC/20190323_042917_12000BPS_APCO25PHASE2_CNYICC_ROME_154_250_6.bits"); +// Path path = Paths.get("/media/denny/500G1EXT4/RadioRecordings/APCO25P2/CNYICC/20190323_042938_12000BPS_APCO25PHASE2_CNYICC_ROME_154_250_7.bits"); + + try(BinaryReader reader = new BinaryReader(path, 200)) + { + while(reader.hasNext()) + { + messageFramer.receive(reader.next()); + } + } + catch(Exception ioe) + { + ioe.printStackTrace(); + } + +// frameRecorder.stop(); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2MessageProcessor.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2MessageProcessor.java new file mode 100644 index 000000000..6228fc7c4 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2MessageProcessor.java @@ -0,0 +1,175 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.message.IMessage; +import io.github.dsheirer.message.SyncLossMessage; +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.phase2.message.EncryptionSynchronizationSequence; +import io.github.dsheirer.module.decode.p25.phase2.message.EncryptionSynchronizationSequenceProcessor; +import io.github.dsheirer.module.decode.p25.phase2.message.SuperFrameFragment; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacMessage; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.AbstractSignalingTimeslot; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.AbstractVoiceTimeslot; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.Timeslot; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.Voice2Timeslot; +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; + +public class P25P2MessageProcessor implements Listener +{ + private final static Logger mLog = LoggerFactory.getLogger(P25P2MessageProcessor.class); + + private EncryptionSynchronizationSequenceProcessor mESSProcessor0 = new EncryptionSynchronizationSequenceProcessor(0); + private EncryptionSynchronizationSequenceProcessor mESSProcessor1 = new EncryptionSynchronizationSequenceProcessor(1); + private Listener 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 + private Map mFrequencyBandMap = new TreeMap(); + + public P25P2MessageProcessor() + { + } + + @Override + public void receive(IMessage message) + { + if(mMessageListener != null) + { + if(message instanceof SuperFrameFragment) + { + SuperFrameFragment sff = (SuperFrameFragment)message; + + for(Timeslot timeslot: sff.getTimeslots()) + { + if(timeslot instanceof AbstractSignalingTimeslot) + { + AbstractSignalingTimeslot ast = (AbstractSignalingTimeslot)timeslot; + + for(MacMessage macMessage: ast.getMacMessages()) + { + /* Insert frequency band identifier update messages into channel-type messages */ + if(macMessage instanceof IFrequencyBandReceiver) + { + IFrequencyBandReceiver receiver = (IFrequencyBandReceiver)macMessage; + + List channels = receiver.getChannels(); + + for(IChannelDescriptor channel : channels) + { + int[] frequencyBandIdentifiers = channel.getFrequencyBandIdentifiers(); + + for(int id : frequencyBandIdentifiers) + { + if(mFrequencyBandMap.containsKey(id)) + { + channel.setFrequencyBand(mFrequencyBandMap.get(id)); + } + } + } + } + + /* Store band identifiers so that they can be injected into channel + * type messages */ + if(macMessage instanceof IFrequencyBand) + { + IFrequencyBand bandIdentifier = (IFrequencyBand)macMessage; + mFrequencyBandMap.put(bandIdentifier.getIdentifier(), bandIdentifier); + } + + mMessageListener.receive(macMessage); + } + } + else if(timeslot instanceof AbstractVoiceTimeslot) + { + if(timeslot.getTimeslot() == 0) + { + mESSProcessor0.process((AbstractVoiceTimeslot)timeslot); + + if(timeslot instanceof Voice2Timeslot) + { + EncryptionSynchronizationSequence ess = mESSProcessor0.getSequence(); + + if(ess != null) + { + mMessageListener.receive(ess); + } + + mESSProcessor0.reset(); + } + } + else + { + mESSProcessor1.process((AbstractVoiceTimeslot)timeslot); + + if(timeslot instanceof Voice2Timeslot) + { + EncryptionSynchronizationSequence ess = mESSProcessor1.getSequence(); + + if(ess != null) + { + mMessageListener.receive(ess); + } + + mESSProcessor1.reset(); + } + } + + mMessageListener.receive(timeslot); + + } + else + { + mMessageListener.receive(timeslot); + } + } + } + else if(message instanceof SyncLossMessage) + { + mMessageListener.receive(message); + } + } + } + + public void dispose() + { + mMessageListener = null; + } + + public void setMessageListener(Listener listener) + { + mMessageListener = listener; + } + + public void removeMessageListener() + { + mMessageListener = null; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2NetworkConfigurationMonitor.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2NetworkConfigurationMonitor.java new file mode 100644 index 000000000..fd2d4fb99 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2NetworkConfigurationMonitor.java @@ -0,0 +1,366 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; +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.AdjacentStatusBroadcastAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.AdjacentStatusBroadcastExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.FrequencyBandUpdate; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.FrequencyBandUpdateTDMA; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.FrequencyBandUpdateVUHF; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.NetworkStatusBroadcastAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.NetworkStatusBroadcastExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.RfssStatusBroadcastAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.RfssStatusBroadcastExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.SecondaryControlChannelBroadcastAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.SecondaryControlChannelBroadcastExplicit; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.SystemServiceBroadcast; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * Tracks the network configuration details of a P25 Phase 2 network from the broadcast messages + */ +public class P25P2NetworkConfigurationMonitor +{ + private final static Logger mLog = LoggerFactory.getLogger(P25P2NetworkConfigurationMonitor.class); + + private Map mFrequencyBandMap = new HashMap<>(); + + //Network Status Messages + private NetworkStatusBroadcastAbbreviated mNetworkStatusBroadcastAbbreviated; + private NetworkStatusBroadcastExtended mNetworkStatusBroadcastExtended; + + //Current Site Status Messages + private RfssStatusBroadcastAbbreviated mRFSSStatusBroadcastAbbreviated; + private RfssStatusBroadcastExtended mRFSSStatusBroadcastExtended; + + //Current Site Secondary Control Channels + private Map mSecondaryControlChannels = new TreeMap<>(); + + //Current Site Services + private SystemServiceBroadcast mSystemServiceBroadcast; + + //Neighbor Sites + private Map mNeighborSitesAbbreviated = new HashMap<>(); + private Map mNeighborSitesExtended = new HashMap<>(); + + /** + * Constructs an instance. + */ + public P25P2NetworkConfigurationMonitor() + { + } + + /** + * Processes network configuration messages. + * + * Note: message is expected to be valid (ie message.isValid() = true) + */ + public void processMacMessage(MacMessage message) + { + MacStructure mac = message.getMacStructure(); + + switch((mac.getOpcode())) + { + case PHASE1_115_IDENTIFIER_UPDATE_TDMA: + if(mac instanceof FrequencyBandUpdateTDMA) + { + FrequencyBandUpdateTDMA tdma = (FrequencyBandUpdateTDMA)mac; + mFrequencyBandMap.put(tdma.getIdentifier(), tdma); + } + break; + case PHASE1_116_IDENTIFIER_UPDATE_V_UHF: + if(mac instanceof FrequencyBandUpdateVUHF) + { + FrequencyBandUpdateVUHF vhf = (FrequencyBandUpdateVUHF)mac; + mFrequencyBandMap.put(vhf.getIdentifier(), vhf); + } + break; + case PHASE1_120_SYSTEM_SERVICE_BROADCAST: + if(mac instanceof SystemServiceBroadcast) + { + mSystemServiceBroadcast = (SystemServiceBroadcast)mac; + } + break; + case PHASE1_121_SECONDARY_CONTROL_CHANNEL_BROADCAST_ABBREVIATED: + if(mac instanceof SecondaryControlChannelBroadcastAbbreviated) + { + SecondaryControlChannelBroadcastAbbreviated sccba = (SecondaryControlChannelBroadcastAbbreviated)mac; + + for(IChannelDescriptor channel: sccba.getChannels()) + { + mSecondaryControlChannels.put(channel.toString(), channel); + } + } + break; + case PHASE1_122_RFSS_STATUS_BROADCAST_ABBREVIATED: + if(mac instanceof RfssStatusBroadcastAbbreviated) + { + mRFSSStatusBroadcastAbbreviated = (RfssStatusBroadcastAbbreviated)mac; + } + break; + case PHASE1_123_NETWORK_STATUS_BROADCAST_ABBREVIATED: + if(mac instanceof NetworkStatusBroadcastAbbreviated) + { + mNetworkStatusBroadcastAbbreviated = (NetworkStatusBroadcastAbbreviated)mac; + } + break; + case PHASE1_124_ADJACENT_STATUS_BROADCAST_ABBREVIATED: + if(mac instanceof AdjacentStatusBroadcastAbbreviated) + { + AdjacentStatusBroadcastAbbreviated asba = (AdjacentStatusBroadcastAbbreviated)mac; + mNeighborSitesAbbreviated.put((int)asba.getSite().getValue(), asba); + } + break; + case PHASE1_125_IDENTIFIER_UPDATE: + if(mac instanceof FrequencyBandUpdate) + { + FrequencyBandUpdate band = (FrequencyBandUpdate)mac; + mFrequencyBandMap.put(band.getIdentifier(), band); + } + break; + case PHASE1_233_SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT: + if(mac instanceof SecondaryControlChannelBroadcastExplicit) + { + SecondaryControlChannelBroadcastExplicit sccbe = (SecondaryControlChannelBroadcastExplicit)mac; + + for(IChannelDescriptor channel: sccbe.getChannels()) + { + mSecondaryControlChannels.put(channel.toString(), channel); + } + } + break; + case PHASE1_250_RFSS_STATUS_BROADCAST_EXTENDED: + if(mac instanceof RfssStatusBroadcastExtended) + { + mRFSSStatusBroadcastExtended = (RfssStatusBroadcastExtended)mac; + } + break; + case PHASE1_251_NETWORK_STATUS_BROADCAST_EXTENDED: + if(mac instanceof NetworkStatusBroadcastExtended) + { + mNetworkStatusBroadcastExtended = (NetworkStatusBroadcastExtended)mac; + } + break; + case PHASE1_252_ADJACENT_STATUS_BROADCAST_EXTENDED: + if(mac instanceof AdjacentStatusBroadcastExtended) + { + AdjacentStatusBroadcastExtended asbe = (AdjacentStatusBroadcastExtended)mac; + mNeighborSitesExtended.put((int)asbe.getSite().getValue(), asbe); + } + break; + } + } + + public void reset() + { + mFrequencyBandMap.clear(); + mNetworkStatusBroadcastAbbreviated = null; + mNetworkStatusBroadcastExtended = null; + mRFSSStatusBroadcastAbbreviated = null; + mRFSSStatusBroadcastExtended = null; + mSecondaryControlChannels.clear(); + mSystemServiceBroadcast = null; + mNeighborSitesAbbreviated.clear(); + mNeighborSitesExtended.clear(); + } + + public String getActivitySummary() + { + StringBuilder sb = new StringBuilder(); + + sb.append("Activity Summary - Decoder:P25 Phase 2"); + + sb.append("\n\nNetwork\n"); + if(mNetworkStatusBroadcastAbbreviated != null) + { + sb.append(" NAC:").append(mNetworkStatusBroadcastAbbreviated.getNAC()); + sb.append(" WACN:").append(mNetworkStatusBroadcastAbbreviated.getWACN()); + sb.append(" SYSTEM:").append(mNetworkStatusBroadcastAbbreviated.getSystem()); + sb.append(" LRA:").append(mNetworkStatusBroadcastAbbreviated.getLRA()); + } + else if(mNetworkStatusBroadcastExtended != null) + { + sb.append(" NAC:").append(mNetworkStatusBroadcastExtended.getNAC()); + sb.append(" WACN:").append(mNetworkStatusBroadcastExtended.getWACN()); + sb.append(" SYSTEM:").append(mNetworkStatusBroadcastExtended.getSystem()); + sb.append(" LRA:").append(mNetworkStatusBroadcastExtended.getLRA()); + } + else + { + sb.append(" UNKNOWN"); + } + + sb.append("\n\nCurrent Site\n"); + if(mRFSSStatusBroadcastAbbreviated != null) + { + sb.append(" SYSTEM:").append(mRFSSStatusBroadcastAbbreviated.getSystem()); + sb.append(" SITE:").append(mRFSSStatusBroadcastAbbreviated.getSite()); + sb.append(" RF SUBSYSTEM:").append(mRFSSStatusBroadcastAbbreviated.getRFSS()); + sb.append(" LOCATION REGISTRATION AREA:").append(mRFSSStatusBroadcastAbbreviated.getLRA()); + sb.append(" PRI CONTROL CHANNEL:").append(mRFSSStatusBroadcastAbbreviated.getChannel()); + sb.append(" DOWNLINK:").append(mRFSSStatusBroadcastAbbreviated.getChannel().getDownlinkFrequency()); + sb.append(" UPLINK:").append(mRFSSStatusBroadcastAbbreviated.getChannel().getUplinkFrequency()).append("\n"); + } + else if(mRFSSStatusBroadcastExtended != null) + { + sb.append(" SYSTEM:").append(mRFSSStatusBroadcastExtended.getSystem()); + sb.append(" SITE:").append(mRFSSStatusBroadcastExtended.getSite()); + sb.append(" RF SUBSYSTEM:").append(mRFSSStatusBroadcastExtended.getRFSS()); + sb.append(" LOCATION REGISTRATION AREA:").append(mRFSSStatusBroadcastExtended.getLRA()); + sb.append(" PRI CONTROL CHANNEL:").append(mRFSSStatusBroadcastExtended.getChannel()); + sb.append(" DOWNLINK:").append(mRFSSStatusBroadcastExtended.getChannel().getDownlinkFrequency()); + sb.append(" UPLINK:").append(mRFSSStatusBroadcastExtended.getChannel().getUplinkFrequency()).append("\n"); + } + else + { + sb.append(" UNKNOWN"); + } + + if(!mSecondaryControlChannels.isEmpty()) + { + List channels = new ArrayList<>(mSecondaryControlChannels.keySet()); + Collections.sort(channels); + + for(String channel : channels) + { + IChannelDescriptor secondaryControlChannel = mSecondaryControlChannels.get(channel); + + if(secondaryControlChannel != null) + { + sb.append(" SEC CONTROL CHANNEL:").append(secondaryControlChannel); + sb.append(" DOWNLINK:").append(secondaryControlChannel.getDownlinkFrequency()); + sb.append(" UPLINK:").append(secondaryControlChannel.getUplinkFrequency()).append("\n"); + } + } + } + + if(mSystemServiceBroadcast != null) + { + sb.append(" AVAILABLE SERVICES:").append(mSystemServiceBroadcast.getAvailableServices()); + sb.append(" SUPPORTED SERVICES:").append(mSystemServiceBroadcast.getSupportedServices()); + } + + + sb.append("\nNeighbor Sites\n"); + Set sites = new TreeSet<>(); + sites.addAll(mNeighborSitesAbbreviated.keySet()); + sites.addAll(mNeighborSitesExtended.keySet()); + + if(sites.isEmpty()) + { + sb.append(" UNKNOWN"); + } + else + { + List sitesSorted = new ArrayList<>(sites); + Collections.sort(sitesSorted); + + for(Integer site : sitesSorted) + { + if(mNeighborSitesAbbreviated.containsKey(site)) + { + AdjacentStatusBroadcastAbbreviated asb = mNeighborSitesAbbreviated.get(site); + sb.append(" SYSTEM:").append(asb.getSystem()); + sb.append(" SITE:").append(asb.getSite()); + sb.append(" LRA:").append(asb.getLRA()); + sb.append(" RFSS:").append(asb.getRFSS()); + sb.append(" CHANNEL:").append(asb.getChannel()); + sb.append(" DOWNLINK:").append(asb.getChannel().getDownlinkFrequency()); + sb.append(" UPLINK:").append(asb.getChannel().getUplinkFrequency()); + sb.append(" STATUS:").append(asb.getSiteFlags()).append("\n"); + } + else if(mNeighborSitesAbbreviated.containsKey(site)) + { + AdjacentStatusBroadcastAbbreviated asb = mNeighborSitesAbbreviated.get(site); + sb.append(" SYSTEM:").append(asb.getSystem()); + sb.append(" SITE:").append(asb.getSite()); + sb.append(" LRA:").append(asb.getLRA()); + sb.append(" RFSS:").append(asb.getRFSS()); + sb.append(" CHANNEL:").append(asb.getChannel()); + sb.append(" DOWNLINK:").append(asb.getChannel().getDownlinkFrequency()); + sb.append(" UPLINK:").append(asb.getChannel().getUplinkFrequency()); + sb.append(" STATUS:").append(asb.getSiteFlags()).append("\n"); + } + else + { + sb.append(" SITE:").append(site).append(" NOT FOUND IN NEIGHBOR SITE MAPS\n"); + } + } + } + + sb.append("\nFrequency Bands\n"); + if(mFrequencyBandMap.isEmpty()) + { + sb.append(" UNKNOWN"); + } + else + { + List ids = new ArrayList<>(mFrequencyBandMap.keySet()); + Collections.sort(ids); + { + for(Integer id : ids) + { + sb.append(" ").append(formatFrequencyBand(mFrequencyBandMap.get(id))).append("\n"); + } + } + } + + return sb.toString(); + } + + /** + * Formats a frequency band + */ + private String formatFrequencyBand(IFrequencyBand band) + { + StringBuilder sb = new StringBuilder(); + sb.append("BAND:").append(band.getIdentifier()); + sb.append(" ").append(band.isTDMA() ? "TDMA" : "FDMA"); + sb.append(" BASE:").append(band.getBaseFrequency()); + sb.append(" BANDWIDTH:").append(band.getBandwidth()); + sb.append(" SPACING:").append(band.getChannelSpacing()); + sb.append(" TRANSMIT OFFSET:").append(band.getTransmitOffset()); + + if(band.isTDMA()) + { + sb.append(" TIMESLOTS:").append(band.getTimeslotCount()); + } + + return sb.toString(); + } + +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2SuperFrameDetector.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2SuperFrameDetector.java new file mode 100644 index 000000000..90c628b25 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2SuperFrameDetector.java @@ -0,0 +1,277 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +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.SyncLossMessage; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters; +import io.github.dsheirer.module.decode.p25.phase2.message.SuperFrameFragment; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacMessage; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacOpcode; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.NetworkStatusBroadcastAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.NetworkStatusBroadcastExtended; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.AbstractSignalingTimeslot; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.ScramblingSequence; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.Timeslot; +import io.github.dsheirer.protocol.Protocol; +import io.github.dsheirer.sample.Listener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * APCO25 Phase 2 super-frame fragment detector uses a sync pattern detector and a circular + * dibit buffer to detect sync patterns and correctly frame a 1440-bit super-frame fragment + * containing 4 timeslots and surrounding ISCH messaging. + */ +public class P25P2SuperFrameDetector implements Listener, ISyncDetectListener +{ + private final static Logger mLog = LoggerFactory.getLogger(P25P2SuperFrameDetector.class); + + private static final int FRAGMENT_DIBIT_LENGTH = 720; + private static final int DIBIT_COUNT_MISALIGNED_SYNC = FRAGMENT_DIBIT_LENGTH - 180; + private static final int BROADCAST_SYNC_LOSS_DIBIT_COUNT = 3720; + private static final int DIBIT_DELAY_BUFFER_INDEX_SYNC_1 = 360; + private static final int DIBIT_DELAY_BUFFER_INDEX_SYNC_2 = 540; + private static final int SYNCHRONIZED_SYNC_MATCH_THRESHOLD = 10; + private static final int UN_SYNCHRONIZED_SYNC_MATCH_THRESHOLD = 4; + + private ScramblingSequence mScramblingSequence = new ScramblingSequence(); + private Listener mMessageListener; + private P25P2SyncDetector mSyncDetector; + private DibitDelayBuffer mSyncDetectionDelayBuffer = new DibitDelayBuffer(160); + private DibitDelayBuffer mFragmentBuffer = new DibitDelayBuffer(720); + private int mDibitsProcessed = 0; + private boolean mSynchronized = false; + + public P25P2SuperFrameDetector(IPhaseLockedLoop phaseLockedLoop) + { + mSyncDetector = new P25P2SyncDetector(this, phaseLockedLoop); + } + + /** + * Sets or updates the scrambling sequence parameters. + * @param scramblingSequence containing updated parameters + */ + public void setScrambleParameters(ScrambleParameters scramblingSequence) + { + mScramblingSequence.update(scramblingSequence); + } + + public void setListener(Listener listener) + { + mMessageListener = listener; + } + + /** + * Sets the sample rate for the phase inversion sync detector + */ + public void setSampleRate(double sampleRate) + { + mSyncDetector.setSampleRate(sampleRate); + } + + public void reset() + { + } + + @Override + public void syncDetected(int bitErrors) + { + checkFragmentSync(bitErrors); + } + + @Override + public void syncLost() + { + } + + private long getCurrentTimestamp() + { + //TODO: implement a dibit counter and timestamp calculator. We should receive a timestamp update with each + //TODO: buffer that arrives. Use the timestamp dibit counter to calculate the exact timestamp of where we're at. + return System.currentTimeMillis(); + } + + @Override + public void receive(Dibit dibit) + { + mDibitsProcessed++; + + mFragmentBuffer.put(dibit); + + if(mSynchronized) + { + mSyncDetectionDelayBuffer.put(dibit); + + if(mDibitsProcessed >= FRAGMENT_DIBIT_LENGTH) + { + checkFragmentSync(0); + } + } + else + { + //Only feed the sync pattern detector if we're not synchronized + Dibit delayed = mSyncDetectionDelayBuffer.getAndPut(dibit); + mSyncDetector.receive(delayed); + } + + //Broadcast sync loss message once a second (3000 dibits/6000 bits) when we're not synchronized + if(mDibitsProcessed > BROADCAST_SYNC_LOSS_DIBIT_COUNT) + { + mDibitsProcessed -= 3000; + broadcastSyncLoss(3000); + } + } + + /** + * Creates a super-frame fragment from the current contents of the fragment dibit buffer and broadcasts it to + * a registered listener. + * + * @param bitErrors detected for first and second ISCH-S segments combined + */ + private void broadcastFragment(int bitErrors) + { + if(mDibitsProcessed > FRAGMENT_DIBIT_LENGTH) + { + broadcastSyncLoss(mDibitsProcessed - FRAGMENT_DIBIT_LENGTH); + } + + mDibitsProcessed = 0; + CorrectedBinaryMessage message = mFragmentBuffer.getMessage(0, 720); + message.setCorrectedBitCount(bitErrors); + SuperFrameFragment frameFragment = new SuperFrameFragment(message, getCurrentTimestamp(), mScramblingSequence); + updateScramblingCode(frameFragment); + broadcast(frameFragment); + } + + private void updateScramblingCode(SuperFrameFragment superFrameFragment) + { + for(Timeslot timeslot: superFrameFragment.getTimeslots()) + { + if(timeslot instanceof AbstractSignalingTimeslot) + { + List macMessages = ((AbstractSignalingTimeslot)timeslot).getMacMessages(); + + for(MacMessage macMessage: macMessages) + { + MacOpcode macOpcode = macMessage.getMacStructure().getOpcode(); + + if(macOpcode == MacOpcode.PHASE1_123_NETWORK_STATUS_BROADCAST_ABBREVIATED && + macMessage.getMacStructure() instanceof NetworkStatusBroadcastAbbreviated) + { + NetworkStatusBroadcastAbbreviated networkStatus = (NetworkStatusBroadcastAbbreviated)macMessage.getMacStructure(); + mScramblingSequence.update(networkStatus.getScrambleParameters()); + } + else if(macOpcode == MacOpcode.PHASE1_251_NETWORK_STATUS_BROADCAST_EXTENDED && + macMessage.getMacStructure() instanceof NetworkStatusBroadcastExtended) + { + NetworkStatusBroadcastExtended networkStatus = (NetworkStatusBroadcastExtended)macMessage.getMacStructure(); + mScramblingSequence.update(networkStatus.getScrambleParameters()); + } + } + } + } + } + + private void broadcastSyncLoss(int dibitsProcessed) + { + broadcast(new SyncLossMessage(getCurrentTimestamp(), dibitsProcessed * 2, Protocol.APCO25_PHASE2)); + } + + private void broadcast(IMessage message) + { + if(mMessageListener != null) + { + mMessageListener.receive(message); + } + } + + + private void checkFragmentSync(int syncDetectorBitErrorCount) + { + //Since we're using multi-sync detection, only proceed if we've processed enough dibits. The first sync detector + //to fire will cause the fragment to be processed and any subsequent, simultaneous detection will be ignored. + if(mDibitsProcessed > 0) + { + if(mSynchronized) + { + //If we're synchronized, then this is a counter based trigger and we check both sync locations + Dibit[] sync1Dibits = mFragmentBuffer.getBuffer(DIBIT_DELAY_BUFFER_INDEX_SYNC_1, 20); + int sync1BitErrorCount = P25P2SyncPattern.getBitErrorCount(sync1Dibits); + + if(sync1BitErrorCount <= SYNCHRONIZED_SYNC_MATCH_THRESHOLD) + { + Dibit[] sync2Dibits = mFragmentBuffer.getBuffer(DIBIT_DELAY_BUFFER_INDEX_SYNC_2, 20); + int sync2BitErrorCount = P25P2SyncPattern.getBitErrorCount(sync2Dibits); + + if(sync2BitErrorCount <= SYNCHRONIZED_SYNC_MATCH_THRESHOLD) + { + broadcastFragment(sync1BitErrorCount + sync2BitErrorCount); + //broadcast message + return; + } + else + { + mSynchronized = false; + return; + } + } + else + { + mSynchronized = false; + return; + } + } + + //If we're not synchronized, this is a sync detector trigger and we only have to check sync 1 for error + // count because the sync detector has already triggered on sync 2 + Dibit[] sync1Dibits = mFragmentBuffer.getBuffer(DIBIT_DELAY_BUFFER_INDEX_SYNC_1, 20); + int sync1BitErrorCount = P25P2SyncPattern.getBitErrorCount(sync1Dibits); + + if(sync1BitErrorCount <= UN_SYNCHRONIZED_SYNC_MATCH_THRESHOLD) + { + mSynchronized = true; + broadcastFragment(sync1BitErrorCount + syncDetectorBitErrorCount); + } + else + { + //We're probably mis-aligned on the fragment. Setup as if we're synchronized and adjust the dibits + // processed counter so that we guarantee a fragment check after another 180 dibits have arrived which + // means that sync1 and sync2 should be aligned + mSynchronized = true; + + if(mDibitsProcessed > DIBIT_COUNT_MISALIGNED_SYNC) + { + broadcastSyncLoss(mDibitsProcessed - DIBIT_COUNT_MISALIGNED_SYNC); + } + + mDibitsProcessed = DIBIT_COUNT_MISALIGNED_SYNC; + } + } + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2SyncDetector.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2SyncDetector.java new file mode 100644 index 000000000..01e8ea52d --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2SyncDetector.java @@ -0,0 +1,168 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.bits.MultiSyncPatternMatcher; +import io.github.dsheirer.bits.SoftSyncDetector; +import io.github.dsheirer.bits.SyncDetector; +import io.github.dsheirer.dsp.psk.pll.IPhaseLockedLoop; +import io.github.dsheirer.dsp.symbol.Dibit; +import io.github.dsheirer.dsp.symbol.FrameSync; +import io.github.dsheirer.dsp.symbol.ISyncDetectListener; +import io.github.dsheirer.sample.Listener; + +public class P25P2SyncDetector implements Listener +{ + /* Determines the threshold for sync pattern soft matching */ + private static final int SYNC_MATCH_THRESHOLD = 4; + + /* Costas Loop phase lock error correction values. A phase lock error of + * 90 degrees requires a correction of 1/4 of the symbol rate (1200Hz). An + * error of 180 degrees requires a correction of 1/2 of the symbol rate */ + public static final double DEFAULT_SAMPLE_RATE = 50000.0; + + public static final double FREQUENCY_PHASE_CORRECTION_90_DEGREES = 1200.0; + public static final double FREQUENCY_PHASE_CORRECTION_180_DEGREES = 2400.0; + + private MultiSyncPatternMatcher mMatcher; + private SoftSyncDetector mPrimarySyncDetector; + + private PLLPhaseInversionDetector mInversionDetector90CW; + private PLLPhaseInversionDetector mInversionDetector90CCW; + private PLLPhaseInversionDetector mInversionDetector180; + + public P25P2SyncDetector(ISyncDetectListener syncDetectListener, IPhaseLockedLoop phaseLockedLoop) + { + //TODO: since we're only going to feed dibits to find next frame, it makes sense to + //TODO: update the sync lost parameter to 48 bits .... + + //TODO: only enable the phase inversion detectors when we're in a sync-lost state + mMatcher = new MultiSyncPatternMatcher(syncDetectListener, 1440, 40); + mPrimarySyncDetector = new SoftSyncDetector(FrameSync.P25_PHASE2_NORMAL.getSync(), SYNC_MATCH_THRESHOLD, syncDetectListener); + mMatcher.add(mPrimarySyncDetector); + + if(phaseLockedLoop != null) + { + //Add additional sync pattern detectors to detect when we get 90/180 degree out of phase sync pattern + //detections so that we can apply correction to the phase locked loop + mInversionDetector90CW = new PLLPhaseInversionDetector(FrameSync.P25_PHASE1_ERROR_90_CW, + phaseLockedLoop, DEFAULT_SAMPLE_RATE, FREQUENCY_PHASE_CORRECTION_90_DEGREES); + mMatcher.add(mInversionDetector90CW); + + mInversionDetector90CCW = new PLLPhaseInversionDetector(FrameSync.P25_PHASE1_ERROR_90_CCW, + phaseLockedLoop, DEFAULT_SAMPLE_RATE, -FREQUENCY_PHASE_CORRECTION_90_DEGREES); + mMatcher.add(mInversionDetector90CCW); + + mInversionDetector180 = new PLLPhaseInversionDetector(FrameSync.P25_PHASE1_ERROR_180, + phaseLockedLoop, DEFAULT_SAMPLE_RATE, FREQUENCY_PHASE_CORRECTION_180_DEGREES); + mMatcher.add(mInversionDetector180); + } + } + + /** + * Calculates the number of bits that match in the current primary detector + * @return + */ + public int getPrimarySyncMatchErrorCount() + { + return Long.bitCount(mMatcher.getCurrentValue() ^ FrameSync.P25_PHASE1_NORMAL.getSync()); + } + + @Override + public void receive(Dibit dibit) + { + mMatcher.receive(dibit.getBit1(), dibit.getBit2()); + } + + /** + * Updates the incoming sample stream sample rate to allow the PLL phase inversion detectors to + * recalculate their internal phase correction values. + * + * @param sampleRate of the incoming sample stream + */ + public void setSampleRate(double sampleRate) + { + mInversionDetector180.setSampleRate(sampleRate); + mInversionDetector90CW.setSampleRate(sampleRate); + mInversionDetector90CCW.setSampleRate(sampleRate); + } + + /** + * Sync pattern detector to listen for costas loop phase lock errors and apply a phase correction to the costas + * loop so that we don't miss any messages. + * + * When the costas loop locks with a +/- 90 degree or 180 degree phase error, the slicer will incorrectly apply + * the symbol pattern rotated left or right by the phase error. However, we can detect these rotated sync patterns + * and apply immediate phase correction so that message processing can continue. + */ + public class PLLPhaseInversionDetector extends SyncDetector + { + private IPhaseLockedLoop mPhaseLockedLoop; + private double mSampleRate; + private double mFrequencyCorrection; + private double mPllCorrection; + + /** + * Constructs the PLL phase inversion detector. + * + * @param frameSync pattern to monitor for detecting phase inversion errors + * @param phaseLockedLoop to receive phase correction values + * @param sampleRate of the incoming sample stream + * @param frequencyCorrection to apply to the PLL. Examples: + * QPSK +/-90 degree correction: +/-SYMBOL RATE / 4.0 + * QPSK 180 degree correction: SYMBOL RATE / 2.0 + */ + public PLLPhaseInversionDetector(FrameSync frameSync, IPhaseLockedLoop phaseLockedLoop, double sampleRate, + double frequencyCorrection) + { + super(frameSync.getSync()); + mPhaseLockedLoop = phaseLockedLoop; + mFrequencyCorrection = frequencyCorrection; + setSampleRate(sampleRate); + + setListener(new ISyncDetectListener() + { + @Override + public void syncDetected(int bitErrors) + { + mPhaseLockedLoop.correctInversion(mPllCorrection); + } + + @Override + public void syncLost() + { + //no-op + } + }); + } + + /** + * Sets or adjusts the sample rate so that the phase inversion correction value can be recalculated. + * @param sampleRate + */ + public void setSampleRate(double sampleRate) + { + mSampleRate = sampleRate; + mPllCorrection = 2.0 * Math.PI * mFrequencyCorrection / mSampleRate; + } + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2SyncPattern.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2SyncPattern.java new file mode 100644 index 000000000..6f2de1f33 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2SyncPattern.java @@ -0,0 +1,64 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2; + +import io.github.dsheirer.dsp.symbol.Dibit; + +public class P25P2SyncPattern +{ + private static final Dibit[] SYNC_PATTERN = { + Dibit.D01_PLUS_3,Dibit.D01_PLUS_3,Dibit.D01_PLUS_3,Dibit.D11_MINUS_3, + Dibit.D01_PLUS_3,Dibit.D01_PLUS_3,Dibit.D11_MINUS_3,Dibit.D01_PLUS_3, + Dibit.D01_PLUS_3,Dibit.D01_PLUS_3,Dibit.D01_PLUS_3,Dibit.D11_MINUS_3, + Dibit.D11_MINUS_3,Dibit.D11_MINUS_3,Dibit.D01_PLUS_3,Dibit.D11_MINUS_3, + Dibit.D11_MINUS_3,Dibit.D11_MINUS_3,Dibit.D11_MINUS_3,Dibit.D11_MINUS_3}; + + public static int getBitErrorCount(Dibit[] dibits) + { + if(dibits.length != 20) + { + throw new IllegalArgumentException("Sync pattern dibit array must be 20 dibits (40 bits) long"); + } + + int bitErrorCount = 0; + + for(int x = 0; x < 20; x++) + { + if(SYNC_PATTERN[x] != dibits[x]) + { + int errorMask = SYNC_PATTERN[x].getLowValue() ^ dibits[x].getLowValue(); + + if(errorMask == 3) + { + bitErrorCount += 2; + } + else + { + bitErrorCount++; + } + } + } + + return bitErrorCount; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/BER.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/BER.java new file mode 100644 index 000000000..ed8a74696 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/BER.java @@ -0,0 +1,69 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.enumeration; + +/** + * Bit Error Rate (BER) + */ +public enum BER +{ + B0("0 - 0.08%"), + B1("0.08-0.12%"), + B2("0.12-0.18%"), + B3("0.18-0.27%"), + B4("0.27-0.39% "), + B5("0.39-0.57%"), + B6("0.57-0.84%"), + B7("0.84-1.25%"), + B8("1.25-1.35%"), + B9("1.35-2.7%"), + B10("2.7-3.9%"), + B11("3.9-5.7%"), + B12("5.7-8.4%"), + B13("8.4-12.5%"), + B14(">12.5%"), + UNUSED("UNUSED"); + + private String mLabel; + + BER(String label) + { + mLabel = label; + } + + @Override + public String toString() + { + return mLabel; + } + + public static BER fromValue(int value) + { + if(0 <= value && value <= 15) + { + return BER.values()[value]; + } + + return UNUSED; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/DataUnitID.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/DataUnitID.java new file mode 100644 index 000000000..1f5387c5d --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/DataUnitID.java @@ -0,0 +1,117 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2.enumeration; + +import java.util.EnumSet; + +/** + * P25 Phase 2 Data Unit ID (DUID) enumeration + */ +public enum DataUnitID +{ + + VOICE_4(0, 0x00,"VOICE-4"), + SCRAMBLED_SACCH(3, 0x39, "SACCH-S"), + VOICE_2(6, 0x65, "VOICE-2"), + SCRAMBLED_FACCH(9, 0x9A, "FACCH-S"), + UNSCRAMBLED_SACCH(12, 0xC6, "SACCH-U"), + UNSCRAMBLED_FACCH(15, 0xFF, "FACCH-U"), + + UNKNOWN(-1, 0x00, "UNKNOWN-"); + + private int mValue; + private int mValueWithParity; + private String mLabel; + + DataUnitID(int value, int valueWithParity, String label) + { + mValue = value; + mValueWithParity = valueWithParity; + mLabel = label; + } + + /** + * Data Unit ID value + */ + public int getValue() + { + return mValue; + } + + /** + * Data Unit ID value with parity bits + */ + public int getValueWithParity() + { + return mValueWithParity; + } + + @Override + public String toString() + { + return mLabel; + } + + public static EnumSet VALID_VALUES = EnumSet.range(VOICE_4, UNSCRAMBLED_FACCH); + + /** + * Lookup the Data Unit ID from an encoded 8-bit integer value that contains the 4-bit duid value and an appended + * 4-bit parity value. + */ + public static DataUnitID fromEncodedValue(int value) + { + int masked = 0xF & (value >> 4); + + switch(masked) + { + case 0: + return VOICE_4; + case 3: + return SCRAMBLED_SACCH; + case 6: + return VOICE_2; + case 9: + return SCRAMBLED_FACCH; + case 12: + return UNSCRAMBLED_SACCH; + case 15: + return UNSCRAMBLED_FACCH; + } + + DataUnitID closest = DataUnitID.UNKNOWN; + int errorCount = 4; + + for(DataUnitID duid: VALID_VALUES) + { + int mask = value ^ duid.getValueWithParity(); + int maskErrorCount = Integer.bitCount(mask); + + if(maskErrorCount < errorCount) + { + errorCount = maskErrorCount; + closest = duid; + } + } + + return closest; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/ISCHSequence.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/ISCHSequence.java new file mode 100644 index 000000000..2cfb1ed7b --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/ISCHSequence.java @@ -0,0 +1,96 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2.enumeration; + +/** + * P25 Phase 2 ISCH Location within a Superframe + */ +public enum ISCHSequence +{ + ISCH_1(0, "FRAG1", 0), + ISCH_2(1, "FRAG2", 4), + ISCH_3(2, "FRAG3", 8), + RESERVED_4(3, "RSVD4", 0), + UNKNOWN(-1, "UNKNO", 0); + + private int mValue; + private String mLabel; + private int mTimeslotOffset; + + ISCHSequence(int value, String label, int timeslotOffset) + { + mValue = value; + mLabel = label; + mTimeslotOffset = timeslotOffset; + } + + /** + * ISCH sequence number value + */ + public int getValue() + { + return mValue; + } + + /** + * Offset to apply to the each of the timeslots in a fragment. + * @return timeslot offset + */ + public int getTimeslotOffset() + { + return mTimeslotOffset; + } + + /** + * Indicates if this sequence is a final fragment sequence + */ + public boolean isFinalFragment() + { + return this == ISCH_3; + } + + @Override + public String toString() + { + return mLabel; + } + + /** + * Lookup the ISCH sequence from an integer value + */ + public static ISCHSequence fromValue(int value) + { + switch(value) + { + case 0: + return ISCH_1; + case 1: + return ISCH_2; + case 2: + return ISCH_3; + case 3: + return RESERVED_4; + default: + return UNKNOWN; + } + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/RFLevel.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/RFLevel.java new file mode 100644 index 000000000..093243751 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/RFLevel.java @@ -0,0 +1,69 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.enumeration; + +/** + * Indicates the RF level adjustment command to a mobile radio + */ +public enum RFLevel +{ + UNKNOWN("UNKNOWN"), + MINUS_15("-15 dBm"), + MINUS_12("-12 dBm"), + MINUS_9("-9 dBm"), + MINUS_6("-6 dBm"), + MINUS_3("-3 dBm"), + NONE("0 dBm"), + PLUS_3("+3 dBm"), + PLUS_6("+6 dBm"), + PLUS_9("+9 dBm"), + PLUS_12("+12 dBm"), + PLUS_15("+15 dBm"), + PLUS_18("+18 dBm"), + PLUS_21("+21 dBm"), + PLUS_24("+24 dBm"), + PLUS_27("+27 dBm"); + + private String mLabel; + + RFLevel(String label) + { + mLabel = label; + } + + @Override + public String toString() + { + return mLabel; + } + + public static RFLevel fromValue(int value) + { + if(0 <= value && value <= 15) + { + return RFLevel.values()[value]; + } + + return UNKNOWN; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/ScrambleParameters.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/ScrambleParameters.java new file mode 100644 index 000000000..bbd23f91b --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/ScrambleParameters.java @@ -0,0 +1,109 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.enumeration; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** + * APCO25 Linear Feedback Shift Register (LFSR) seed parameters. + */ +public class ScrambleParameters +{ + private int mWacn; + private int mSystem; + private int mNac; + + public ScrambleParameters() + { + //no-arg constructor for jackson deserialization + } + + /** + * Constructs a parameters instance + */ + public ScrambleParameters(int wacn, int system, int nac) + { + mWacn = wacn; + mSystem = system; + mNac = nac; + } + + /** + * WACN + * @return wacn + */ + @JacksonXmlProperty(isAttribute = true, localName = "wacn") + public int getWACN() + { + return mWacn; + } + + public void setWacn(int wacn) + { + mWacn = wacn; + } + + /** + * System + * @return system + */ + @JacksonXmlProperty(isAttribute = true, localName = "system") + public int getSystem() + { + return mSystem; + } + + public void setSystem(int system) + { + mSystem = system; + } + + /** + * NAC + * @return nac + */ + @JacksonXmlProperty(isAttribute = true, localName = "nac") + public int getNAC() + { + return mNac; + } + + public void setNAC(int nac) + { + mNac = nac; + } + + /** + * Creates a copy of this instance. + */ + public ScrambleParameters copy() + { + return new ScrambleParameters(mWacn, mSystem, mNac); + } + + @Override + public String toString() + { + return "SCRAMBLE PARAMETERS WACN:" + mWacn + " SYSTEM:" + mSystem + " NAC:" + mNac; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/SuperframeSequence.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/SuperframeSequence.java new file mode 100644 index 000000000..4ba72fd2f --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/SuperframeSequence.java @@ -0,0 +1,77 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.phase2.enumeration; + +/** + * P25 Phase 2 Superframe location within an Ultraframe + */ +public enum SuperframeSequence +{ + SUPERFRAME_1(0, "SF1"), + SUPERFRAME_2(1, "SF2"), + SUPERFRAME_3(2, "SF3"), + SUPERFRAME_4(3, "SF4"), + UNKNOWN(-1, "UNK"); + + private int mValue; + private String mLabel; + + SuperframeSequence(int value, String label) + { + mValue = value; + mLabel = label; + } + + /** + * Superframe sequence number value + */ + public int getValue() + { + return mValue; + } + + @Override + public String toString() + { + return mLabel; + } + + /** + * Lookup the superframe sequence from an integer value + */ + public static SuperframeSequence fromValue(int value) + { + switch(value) + { + case 0: + return SUPERFRAME_1; + case 1: + return SUPERFRAME_2; + case 2: + return SUPERFRAME_3; + case 3: + return SUPERFRAME_4; + default: + return UNKNOWN; + } + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/Voice4VOffset.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/Voice4VOffset.java new file mode 100644 index 000000000..e6f038396 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/enumeration/Voice4VOffset.java @@ -0,0 +1,62 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.enumeration; + +/** + * Indicates the offset from a current MAC message to the next start of a 4V voice frame sequence + */ +public enum Voice4VOffset +{ + SLOTS_1("NEXT NON-SACCH SLOT"), + SLOTS_2("2 NON-SACCH SLOTS"), + SLOTS_3("3 NON-SACCH SLOTS"), + SLOTS_4("4 NON-SACCH SLOTS"), + SLOTS_5("5 NON-SACCH SLOTS"), + SLOTS_6("6 NON-SACCH SLOTS"), + INBOUND("INBOUND"), + NO_VOICE("NO VOICE FRAMING"), + UNKNOWN("UNKNOWN"); + + private String mLabel; + + Voice4VOffset(String label) + { + mLabel = label; + } + + @Override + public String toString() + { + return mLabel; + } + + public static Voice4VOffset fromValue(int value) + { + if(0 <= value && value <= 7) + { + return Voice4VOffset.values()[value]; + } + + return UNKNOWN; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/EncryptionSynchronizationSequence.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/EncryptionSynchronizationSequence.java new file mode 100644 index 000000000..4308e95fb --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/EncryptionSynchronizationSequence.java @@ -0,0 +1,158 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message; + +import io.github.dsheirer.audio.codec.mbe.IEncryptionSyncParameters; +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.encryption.APCO25EncryptionKey; + +import java.util.ArrayList; +import java.util.List; + +/** + * APCO25 Phase II Encryption Synchronization Sequence (ESS). Provides encryption algorithm, key ID and message + * indicator (key generator fill/seed sequence). + */ +public class EncryptionSynchronizationSequence extends P25P2Message implements IEncryptionSyncParameters +{ + private static final int[] ALGORITHM = new int[]{0, 1, 2, 3, 4, 5, 6, 7}; + private static final int[] KEY_ID = new int[]{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] MESSAGE_INDICATOR_1 = new int[]{24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] MESSAGE_INDICATOR_2 = new int[]{32, 33, 34, 35, 36, 37, 38, 39}; + private static final int[] MESSAGE_INDICATOR_3 = new int[]{40, 41, 42, 43, 44, 45, 46, 47}; + private static final int[] MESSAGE_INDICATOR_4 = new int[]{48, 49, 50, 51, 52, 53, 54, 55}; + private static final int[] MESSAGE_INDICATOR_5 = new int[]{56, 57, 58, 59, 60, 61, 62, 63}; + private static final int[] MESSAGE_INDICATOR_6 = new int[]{64, 65, 66, 67, 68, 69, 70, 71}; + private static final int[] MESSAGE_INDICATOR_7 = new int[]{72, 73, 74, 75, 76, 77, 78, 79}; + private static final int[] MESSAGE_INDICATOR_8 = new int[]{80, 81, 82, 83, 84, 85, 86, 87}; + private static final int[] MESSAGE_INDICATOR_9 = new int[]{88, 89, 90, 91, 92, 93, 94, 95}; + + private BinaryMessage mMessage; + private EncryptionKeyIdentifier mEncryptionKey; + private int mTimeslot; + + public EncryptionSynchronizationSequence(BinaryMessage message, int timeslot, long timestamp) + { + super(timestamp); + mMessage = message; + mTimeslot = timeslot; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append("TS").append(mTimeslot); + sb.append(" ESS ").append(getEncryptionKey().toString()); + + if(isEncrypted()) + { + sb.append(" MI:").append(getMessageIndicator()); + } + + return sb.toString(); + } + + /** + * Encryption key identifier that identifies the algorithm and specific key identifier. + * + * NOTE: check isValid() before accessing this method, otherwise this method can return a null value. + * + * @return encryption key or null + */ + @Override + public EncryptionKeyIdentifier getEncryptionKey() + { + if(mEncryptionKey == null && isValid()) + { + mEncryptionKey = EncryptionKeyIdentifier.create(APCO25EncryptionKey.create(getAlgorithmId(), getEncryptionKeyId())); + } + + return mEncryptionKey; + } + + /** + * APCO-25 encryption algorithm numeric identifier + */ + public int getAlgorithmId() + { + return mMessage.getInt(ALGORITHM); + } + + /** + * Indicates if the audio associated with this sequence is encrypted. + */ + public boolean isEncrypted() + { + return getEncryptionKey() != null && getEncryptionKey().isEncrypted(); + } + + /** + * Encryption key identifier + */ + public int getEncryptionKeyId() + { + return mMessage.getInt(KEY_ID); + } + + /** + * Encryption message indicator or fill/seed sequence. + */ + @Override + public String getMessageIndicator() + { + StringBuilder sb = new StringBuilder(); + sb.append(mMessage.getHex(MESSAGE_INDICATOR_1, 2).toUpperCase()); + sb.append(mMessage.getHex(MESSAGE_INDICATOR_2, 2).toUpperCase()); + sb.append(mMessage.getHex(MESSAGE_INDICATOR_3, 2).toUpperCase()); + sb.append(mMessage.getHex(MESSAGE_INDICATOR_4, 2).toUpperCase()); + sb.append(mMessage.getHex(MESSAGE_INDICATOR_5, 2).toUpperCase()); + sb.append(mMessage.getHex(MESSAGE_INDICATOR_6, 2).toUpperCase()); + sb.append(mMessage.getHex(MESSAGE_INDICATOR_7, 2).toUpperCase()); + sb.append(mMessage.getHex(MESSAGE_INDICATOR_8, 2).toUpperCase()); + sb.append(mMessage.getHex(MESSAGE_INDICATOR_9, 2).toUpperCase()); + return sb.toString(); + } + + @Override + public boolean isValid() + { + return true; + } + + @Override + public int getTimeslot() + { + return mTimeslot; + } + + @Override + public List getIdentifiers() + { + List identifiers = new ArrayList<>(); + identifiers.add(getEncryptionKey()); + return identifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/EncryptionSynchronizationSequenceProcessor.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/EncryptionSynchronizationSequenceProcessor.java new file mode 100644 index 000000000..3f7082880 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/EncryptionSynchronizationSequenceProcessor.java @@ -0,0 +1,247 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.edac.ReedSolomon_44_16_29; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.AbstractVoiceTimeslot; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.Voice2Timeslot; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.Voice4Timeslot; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * APCO25 Phase II Encryption Synchronization Sequence (ESS). Provides encryption algorithm, key ID and message + * indicator (key generator fill/seed sequence). + * + * The ESS is transmitted as a sequence of 5 fragments, each in a different voice timeslot. A minimum of the ESS-A + * and at least 1 of the 4 ESS-B fragments is required in order to attempt reed solomon error detection and correction. + * + * Once the minimum fragment requirement is met and the EDAC is successfully completed, further attempts to assign + * ESS fragments are ignored. Check isValid() after each fragment assignment to determine when to access the encryption + * parameters. + */ +public class EncryptionSynchronizationSequenceProcessor +{ + private final static Logger mLog = LoggerFactory.getLogger(EncryptionSynchronizationSequenceProcessor.class); + + private BinaryMessage mESSA; + private BinaryMessage mESSB1; + private BinaryMessage mESSB2; + private BinaryMessage mESSB3; + private BinaryMessage mESSB4; + private int mEssBCounter = 1; + private int mTimeslot; + private long mTimestamp; + + /** + * Constructs an instance + */ + public EncryptionSynchronizationSequenceProcessor(int timeslot) + { + mTimeslot = timeslot; + } + + public void process(AbstractVoiceTimeslot abstractVoiceTimeslot) + { + if(abstractVoiceTimeslot instanceof Voice2Timeslot) + { + setESSA(((Voice2Timeslot)abstractVoiceTimeslot).getEssA()); + mTimestamp = abstractVoiceTimeslot.getTimestamp(); + } + else if(abstractVoiceTimeslot instanceof Voice4Timeslot) + { + Voice4Timeslot voice4Timeslot = (Voice4Timeslot)abstractVoiceTimeslot; + + switch(mEssBCounter) + { + case 1: + setESSB1(voice4Timeslot.getEssB()); + mEssBCounter++; + break; + case 2: + setESSB2(voice4Timeslot.getEssB()); + mEssBCounter++; + break; + case 3: + setESSB3(voice4Timeslot.getEssB()); + mEssBCounter++; + break; + case 4: + setESSB4(voice4Timeslot.getEssB()); + mEssBCounter = 1; + break; + } + } + } + + /** + * Resets this sequence so that a new sequence can be assembled + */ + public void reset() + { + mESSA = null; + mESSB1 = null; + mESSB2 = null; + mESSB3 = null; + mESSB4 = null; + mEssBCounter = 1; + } + + + /** + * Constructs and returns an encryption synchronization sequence if possible, otherwise returns a null sequence. + * The sequence can be created once the minimum quantity of fragments are loaded (ie ESS-A and one of the ESS-B fragments). + */ + public EncryptionSynchronizationSequence getSequence() + { + //We need a minimum of ESS-A and at least one of the ESS-B sequences before we can decode. The Reed Solomon + //code can correct up to 14 symbol errors across the 16 info symbols provided by ESS-B and the 28 parity symbols + //provided by ESS-A + if(mESSA != null && (mESSB1 != null || mESSB2 != null || mESSB3 != null || mESSB4 != null)) + { + //We have to reverse the order of the information hexbits and the RS parity hexbits in the array for + //the RS algorithm. + int[] input = new int[63]; + + int inputPointer = 0; + + for(int x = 27; x >= 0; x--) + { + input[inputPointer++] = mESSA.getInt(x * 6, x * 6 + 5); + } + + if(mESSB4 != null) + { + for(int x = 3; x >= 0; x--) + { + input[inputPointer++] = mESSB4.getInt(x * 6, x * 6 + 5); + } + } + else + { + inputPointer += 4; + } + + if(mESSB3 != null) + { + for(int x = 3; x >= 0; x--) + { + input[inputPointer++] = mESSB3.getInt(x * 6, x * 6 + 5); + } + } + else + { + inputPointer += 4; + } + + if(mESSB2 != null) + { + for(int x = 3; x >= 0; x--) + { + input[inputPointer++] = mESSB2.getInt(x * 6, x * 6 + 5); + } + } + else + { + inputPointer += 4; + } + + if(mESSB1 != null) + { + for(int x = 3; x >= 0; x--) + { + input[inputPointer++] = mESSB1.getInt(x * 6, x * 6 + 5); + } + } + + int[] output = new int[63]; + + ReedSolomon_44_16_29 rs = new ReedSolomon_44_16_29(); + + boolean irrecoverableErrors = rs.decode(input, output); + + if(!irrecoverableErrors) + { + //Transfer error corrected output to a new binary message + BinaryMessage message = new BinaryMessage(96); + + int pointer = 0; + + for(int x = 43; x >= 28; x--) + { + if(output[x] != -1) + { + message.load(pointer, 6, output[x]); + } + + pointer += 6; + } + + return new EncryptionSynchronizationSequence(message, mTimeslot, mTimestamp); + } + } + + return null; + } + + /** + * ESS-B fragment 1 + */ + public void setESSB1(BinaryMessage essB1) + { + mESSB1 = essB1; + } + + /** + * ESS-B fragment 2 + */ + public void setESSB2(BinaryMessage essB2) + { + mESSB2 = essB2; + } + + /** + * ESS-B fragment 3 + */ + public void setESSB3(BinaryMessage essB3) + { + mESSB3 = essB3; + } + + /** + * ESS-B fragment 4 + */ + public void setESSB4(BinaryMessage essB4) + { + mESSB4 = essB4; + } + + /** + * ESS-A fragment + */ + public void setESSA(BinaryMessage essA) + { + mESSA = essA; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/InterSlotSignallingChannel.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/InterSlotSignallingChannel.java new file mode 100644 index 000000000..289d4f332 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/InterSlotSignallingChannel.java @@ -0,0 +1,266 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.ISCHSequence; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.SuperframeSequence; +import org.apache.commons.math3.linear.MatrixUtils; +import org.apache.commons.math3.linear.RealMatrix; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.TreeMap; + +/** + * Inter-slot signalling channel informational (ISCH-I) parsing class + */ +public class InterSlotSignallingChannel +{ + private final static Logger mLog = LoggerFactory.getLogger(InterSlotSignallingChannel.class); + + private static Map sCodewordMap = new TreeMap<>(); + + static + { + double[][] matrix = {{1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,0,1,1,0,0,1,1,1,0,0,0,1,1,0,1,1,0,1,1,0,1,0,1,1,1}, + {0,0,1,0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0}, + {0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,0,1,0,0,1,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,0,0}, + {0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,0,1,1,0,1,0,0,0,1,1,0,0,0,1,1,1,0}, + {0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1}, + {0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,1,0,0,1,0}, + {0,0,0,0,0,0,0,0,1,0,0,1,1,1,0,1,1,0,1,0,0,0,1,1,1,0,1,0,0,0,0,1,0,1,1,1,0,0,0,1}, + {0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,1,1,0,0,1,0,1,1,1,0,1,0,1,0,1,0,0,1,0,0,1,1,1,0}, + {0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,1,1,1,0,1,1,0,0,0,0,1,0,1,1,0,0,1,0,1,1,1}}; + + RealMatrix generator = MatrixUtils.createRealMatrix(matrix); + + //We only generate a lookup map for 7/10 least significant bits since MSB and reserved bits are not used + for(int x = 0; x < 128; x++) + { + RealMatrix word = toMatrix10(x); + RealMatrix codewordMatrix = word.multiply(generator); + long codeword = decodeMatrix(codewordMatrix); + codeword ^= 0x184229d461l; + BinaryMessage message = new BinaryMessage(9); + message.load(0, 9, x); + + sCodewordMap.put(codeword, message); + } + } + + private static final int[] RESERVED = {0, 1}; + private static final int[] CHANNEL_NUMBER = {2, 3}; + private static final int[] ISCH_SEQUENCE = {4, 5}; + private static final int INBOUND_SACCH_FREE_INDICATOR = 6; + private static final int[] SUPERFRAME_SEQUENCE = {7, 8}; + + private CorrectedBinaryMessage mMessage; + private boolean mValid; + + /** + * Constructs the ISCH-I parsing class + * + * @param message containing bits + * @param expectedTimeslot for this ISCH, either channel 0 or channel 1 to assist with validating the message + */ + public InterSlotSignallingChannel(BinaryMessage message, int expectedTimeslot) + { + decode(message); + mValid = (getMessage().getCorrectedBitCount() < 9) && (getTimeslot() == expectedTimeslot); + } + + /** + * Decodes the 40-bit message codeword into an error-corrected 9-bit message + * @param message containing 40 bit codeword + */ + private void decode(BinaryMessage message) + { + long codeword = message.getLong(0, 39); + + if(sCodewordMap.containsKey(codeword)) + { + mMessage = new CorrectedBinaryMessage(sCodewordMap.get(codeword)); + } + else + { + int smallestErrorCount = 16; + long closestCodeword = 0; + + for(long validCodeword: sCodewordMap.keySet()) + { + long mask = codeword & validCodeword; + int errorCount = Long.bitCount(mask); + + if(errorCount < smallestErrorCount) + { + smallestErrorCount = errorCount; + closestCodeword = validCodeword; + } + } + + if(closestCodeword != 0) + { + mMessage = new CorrectedBinaryMessage(sCodewordMap.get(closestCodeword)); + mMessage.setCorrectedBitCount(smallestErrorCount); + } + else + { + //This shouldn't happen, but we'll set bit error count to 9 to indicate a bad decode + mMessage = new CorrectedBinaryMessage(9); + mMessage.setCorrectedBitCount(9); + } + } + } + + /** + * Indicates if this message is valid + */ + public boolean isValid() + { + return mValid; + } + + /** + * Bit error count or the number of bits that were corrected while decoding the transmitted 40-bit codeword + */ + public int getBitErrorCount() + { + return getMessage().getCorrectedBitCount(); + } + + /** + * Decoded and corrected 9-bit message + */ + private CorrectedBinaryMessage getMessage() + { + return mMessage; + } + + /** + * Timeslot for this ISCH + * + * @return timeslot 0 or 1 + */ + public int getTimeslot() + { + return getMessage().getInt(CHANNEL_NUMBER); + } + + /** + * Indicates this ISCH sequence's location within a super-frame + * + * @return location 1, 2, or 3(final) + */ + public ISCHSequence getIschSequence() + { + return ISCHSequence.fromValue(getMessage().getInt(ISCH_SEQUENCE)); + } + + /** + * Indicates if the next inbound SACCH timeslot is free for mobile access + * + * @return true if the inbound SACCH is free + */ + public boolean isInboundSacchFree() + { + return getMessage().get(INBOUND_SACCH_FREE_INDICATOR); + } + + /** + * Superframe sequence/location within an ultraframe + * + * @return location, 1-4 + */ + public SuperframeSequence getSuperframeSequence() + { + return SuperframeSequence.fromValue(getMessage().getInt(SUPERFRAME_SEQUENCE)); + } + + /** + * Decoded string representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + + if(isValid()) + { + sb.append("ISCHI ").append(getTimeslot()); + sb.append(" ").append(getIschSequence()); + sb.append(" ").append(getSuperframeSequence()); + sb.append(isInboundSacchFree() ? " SACCH:FREE" : " SACCH:BUSY"); + } + else + { + sb.append("ISCHI **INVALID** "); + } + + return sb.toString(); + } + + /** + * Creates a 10-element matrix from the value. + * @param value in range 0 - 127 + * @return matrix + */ + private static RealMatrix toMatrix10(int value) + { + double[] values = new double[9]; + for(int x = 0; x < 7; x++) + { + int mask = (int)Math.pow(2, x); + if((value & mask) == mask) + { + values[8 - x] = 1; + } + } + + return MatrixUtils.createRowRealMatrix(values); + } + + /** + * Decodes the matrix which is assumed to be a single row with 40 elements representing bits + * @param matrix to decode + * @return long value + */ + private static long decodeMatrix(RealMatrix matrix) + { + long decoded = 0; + double[] values = matrix.getRow(0); + + for(int x = 0; x < 40; x++) + { + int value = (int)values[39 - x]; + + if((value & 1) == 1) + { + decoded += (long)Math.pow(2, x); + } + } + + return decoded; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/P25MessageFactory.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/P25MessageFactory.java new file mode 100644 index 000000000..134ee59f0 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/P25MessageFactory.java @@ -0,0 +1,28 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message; + +public class P25MessageFactory +{ + +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/P25P2Message.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/P25P2Message.java new file mode 100644 index 000000000..4637062e0 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/P25P2Message.java @@ -0,0 +1,86 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message; + +import io.github.dsheirer.message.IMessage; +import io.github.dsheirer.protocol.Protocol; + +/** + * APCO25 Phase 2 Base Message + */ +public abstract class P25P2Message implements IMessage +{ + private long mTimestamp; + private boolean mValid = true; + + /** + * Constructs the message + * @param timestamp of the final bit of the message + */ + protected P25P2Message(long timestamp) + { + mTimestamp = timestamp; + } + + /** + * Timestamp when the final bit of this message was transmitted + * @return timestamp as milliseconds since epoch + */ + @Override + public long getTimestamp() + { + return mTimestamp; + } + + /** + * Indicates if this message is valid + */ + @Override + public boolean isValid() + { + return mValid; + } + + /** + * Sets the valid flag for this message + */ + public void setValid(boolean valid) + { + mValid = valid; + } + + /** + * Protocol for this message + */ + @Override + public Protocol getProtocol() + { + return Protocol.APCO25_PHASE2; + } + + /** + * Indicates the timeslot, 0 or 1, for this message + */ + @Override + public abstract int getTimeslot(); +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/SuperFrameFragment.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/SuperFrameFragment.java new file mode 100644 index 000000000..f5e47d6de --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/SuperFrameFragment.java @@ -0,0 +1,354 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.message.IMessage; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.ISCHSequence; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.ScramblingSequence; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.Timeslot; +import io.github.dsheirer.module.decode.p25.phase2.timeslot.TimeslotFactory; +import io.github.dsheirer.protocol.Protocol; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * APCO25 Phase 2 SuperFrame fragment containing 4 timeslots. Each superframe contains 12 timeslots and + * this fragment represents 1/3 of a superframe. + */ +public class SuperFrameFragment implements IMessage +{ + private static final int CHANNEL_A_ISCH_START = 0; + private static final int TIMESLOT_A_START = 40; + + private static final int CHANNEL_B_ISCH_START = 360; + private static final int TIMESLOT_B_START = 400; + + private static final int CHANNEL_C_ISCH_START = 720; + private static final int TIMESLOT_C_START = 760; + + private static final int CHANNEL_D_ISCH_START = 1080; + private static final int TIMESLOT_D_START = 1120; + private static final int TIMESLOT_D_END = 1440; + + private long mTimestamp; + private CorrectedBinaryMessage mMessage; + private InterSlotSignallingChannel mChannel0Isch; + private InterSlotSignallingChannel mChannel1Isch; + private Timeslot mTimeslotA; + private Timeslot mTimeslotB; + private Timeslot mTimeslotC; + private Timeslot mTimeslotD; + private ScramblingSequence mScramblingSequence; + + /** + * Constructs a fragment from the message with the specified timestamp. + * + * @param message containing 1440-bit super-frame fragment (ie 1/3 of a superframe) + * @param timestamp of the final bit of this fragment + */ + public SuperFrameFragment(CorrectedBinaryMessage message, long timestamp, ScramblingSequence scramblingSequence) + { + mMessage = message; + mTimestamp = timestamp; + mScramblingSequence = scramblingSequence; + } + + /** + * Transmitted binary message that represents this fragment + */ + protected CorrectedBinaryMessage getMessage() + { + return mMessage; + } + + + /** + * Unused. Implements the parent class abstract method. + */ + @Override + public int getTimeslot() + { + return 0; + } + + /** + * Timestamp for the final bit of this fragment + */ + @Override + public long getTimestamp() + { + return mTimestamp; + } + + /** + * Channel 0 Inter-slot Signalling CHannel (ISCH) + */ + public InterSlotSignallingChannel getIschChannel0() + { + if(mChannel0Isch == null) + { + mChannel0Isch = new InterSlotSignallingChannel( + getMessage().getSubMessage(CHANNEL_A_ISCH_START, TIMESLOT_A_START), 0); + } + + return mChannel0Isch; + } + + /** + * Channel 1 Inter-slot Signalling CHannel (ISCH) + */ + public InterSlotSignallingChannel getIschChannel1() + { + if(mChannel1Isch == null) + { + mChannel1Isch = new InterSlotSignallingChannel( + getMessage().getSubMessage(CHANNEL_B_ISCH_START, TIMESLOT_B_START), 1); + } + + return mChannel1Isch; + } + + /** + * Timeslot A + */ + public Timeslot getTimeslotA() + { + if(mTimeslotA == null) + { + mTimeslotA = getTimeslot(TIMESLOT_A_START, CHANNEL_B_ISCH_START, 0, 0); + } + + return mTimeslotA; + } + + /** + * Timeslot B + */ + public Timeslot getTimeslotB() + { + if(mTimeslotB == null) + { + mTimeslotB = getTimeslot(TIMESLOT_B_START, CHANNEL_C_ISCH_START, 1, 1); + } + + return mTimeslotB; + } + + /** + * Timeslot C + */ + public Timeslot getTimeslotC() + { + if(mTimeslotC == null) + { + mTimeslotC = getTimeslot(TIMESLOT_C_START, CHANNEL_D_ISCH_START, 2, + isFinalFragment() ? 1 : 0); + } + + return mTimeslotC; + } + + /** + * Timeslot D + */ + public Timeslot getTimeslotD() + { + if(mTimeslotD == null) + { + mTimeslotD = getTimeslot(TIMESLOT_D_START, TIMESLOT_D_END, 3, + isFinalFragment() ? 0 : 1); + } + + return mTimeslotD; + } + + public List getTimeslots() + { + List timeslots = new ArrayList<>(); + timeslots.add(getTimeslotA()); + timeslots.add(getTimeslotB()); + + if(isFinalFragment()) + { + timeslots.add(getTimeslotD()); + timeslots.add(getTimeslotC()); + } + else + { + timeslots.add(getTimeslotC()); + timeslots.add(getTimeslotD()); + } + + return timeslots; + } + + /** + * Channel 0 timeslots + */ + public List getChannel0Timeslots() + { + List timeslots = new ArrayList<>(); + timeslots.add(getTimeslotA()); + + if(isFinalFragment()) + { + timeslots.add(getTimeslotD()); + } + else + { + timeslots.add(getTimeslotC()); + } + + return timeslots; + } + + /** + * Channel 1 timeslots + */ + public List getChannel1Timeslots() + { + List timeslots = new ArrayList<>(); + + timeslots.add(getTimeslotB()); + + if(isFinalFragment()) + { + timeslots.add(getTimeslotC()); + } + else + { + timeslots.add(getTimeslotD()); + } + + return timeslots; + } + + /** + * Extracts the timeslot from the parent message and creates a timeslot parser instance + * + * @param start bit of the timeslot + * @param end bit for the message (exclusive) + * @param index of the timeslot (0-11) + * @return timeslot parser instance + */ + private Timeslot getTimeslot(int start, int end, int index, int timeslot) + { + CorrectedBinaryMessage message = getMessage().getSubMessage(start, end); + BinaryMessage timeslotSequence = mScramblingSequence.getTimeslotSequence(getTimeslotOffset() + index); + return TimeslotFactory.getTimeslot(message, timeslotSequence, timeslot, getTimestamp()); + } + + /** + * Indicates the timeslot (index) offset to apply to each of the timeslots in this fragment + */ + private int getTimeslotOffset() + { + ISCHSequence sequence0 = getIschChannel0().getIschSequence(); + + if(getIschChannel0().isValid()) + { + return sequence0.getTimeslotOffset(); + } + + ISCHSequence sequence1 = getIschChannel1().getIschSequence(); + if(getIschChannel1().isValid()) + { + return sequence1.getTimeslotOffset(); + } + + return 0; + } + + /** + * Indicates if this fragment is the final fragment (3 of 3) for a superframe which indicates that the final two + * timeslots are inverted. + */ + private boolean isFinalFragment() + { + ISCHSequence sequence0 = getIschChannel0().getIschSequence(); + + if(getIschChannel0().isValid()) + { + return sequence0.isFinalFragment(); + } + + ISCHSequence sequence1 = getIschChannel1().getIschSequence(); + if(getIschChannel1().isValid()) + { + return sequence1.isFinalFragment(); + } + + //Can't determine, so higher probability is that it's not the final fragment + return false; + } + + /** + * Indicates if this fragment is valid + */ + @Override + public boolean isValid() + { + //TODO: can we do validity checking here?? + return true; + } + + /** + * Proocol for this fragment + */ + @Override + public Protocol getProtocol() + { + return Protocol.APCO25_PHASE2; + } + + /** + * No identifiers for this message + */ + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } + + /** + * Decoded representation of this fragment + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + + sb.append(getIschChannel0()); + sb.append(" | ").append(getIschChannel1()); + sb.append(" | Channel 0:").append(getChannel0Timeslots()); + sb.append(" | Channel 1:").append(getChannel1Timeslots()); + + return sb.toString(); +// return getMessage().toHexString() + " SYNC BIT ERRORS:" + getMessage().getCorrectedBitCount() + +// " | " + getIschChannel0().toString() + " | " + getIschChannel1().toString(); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacMessage.java new file mode 100644 index 000000000..1a9247dff --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacMessage.java @@ -0,0 +1,148 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.Voice4VOffset; +import io.github.dsheirer.module.decode.p25.phase2.message.P25P2Message; + +import java.util.List; + +/** + * Encoded MAC Information (EMI) Message base class + */ +public class MacMessage extends P25P2Message +{ + private static int[] PDU_TYPE = {0, 1, 2}; + private static int[] OFFSET_TO_NEXT_VOICE_4V_START = {3, 4, 5}; + private static int[] RESERVED = {6, 7}; + + private int mChannelNumber; + private DataUnitID mDataUnitID; + private CorrectedBinaryMessage mMessage; + private MacStructure mMacStructure; + + /** + * Constructs the message + * + * @param timeslot for this message + * @param message containing underlying transmitted bits + * @param timestamp of the final bit of the message + * @param macStructure for the payload + */ + public MacMessage(int timeslot, DataUnitID dataUnitID, CorrectedBinaryMessage message, + long timestamp, MacStructure macStructure) + { + super(timestamp); + mChannelNumber = timeslot; + mDataUnitID = dataUnitID; + mMessage = message; + mMacStructure = macStructure; + } + + /** + * Timeslot / Channel number for this message + */ + public int getTimeslot() + { + return mChannelNumber; + } + + /** + * Data Unit ID or timeslot type for this message + */ + public DataUnitID getDataUnitID() + { + return mDataUnitID; + } + + /** + * Underlying binary message as transmitted and error-correctede + */ + protected CorrectedBinaryMessage getMessage() + { + return mMessage; + } + + /** + * MAC structure parser/payload for this message + */ + public MacStructure getMacStructure() + { + return mMacStructure; + } + + /** + * MAC opcode identifies the type of MAC PDU for this message + */ + public MacPduType getMacPduType() + { + return getMacPduTypeFromMessage(getMessage()); + } + + /** + * Lookup the MAC opcode from the message + * @param message containing a mac opcode + * @return opcode + */ + public static MacPduType getMacPduTypeFromMessage(CorrectedBinaryMessage message) + { + return MacPduType.fromValue(message.getInt(PDU_TYPE)); + } + + /** + * Offset to the next Voice 4V start sequence + */ + public Voice4VOffset getOffsetToNextVoice4VStart() + { + return Voice4VOffset.fromValue(getMessage().getInt(OFFSET_TO_NEXT_VOICE_4V_START)); + } + + @Override + public List getIdentifiers() + { + return getMacStructure().getIdentifiers(); + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append("TS").append(getTimeslot()); + sb.append(" ").append(getDataUnitID()); + + if(isValid()) + { + sb.append(" ").append(getMacPduType().toString()); + sb.append(" ").append(getMacStructure().toString()); + } + else + { + sb.append(" INVALID/CRC ERROR"); + } + + return sb.toString(); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacMessageFactory.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacMessageFactory.java new file mode 100644 index 000000000..938f62741 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacMessageFactory.java @@ -0,0 +1,337 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.AcknowledgeResponse; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.AdjacentStatusBroadcastAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.AdjacentStatusBroadcastExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.CallAlertAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.CallAlertExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.DateAndTimeAnnouncement; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.DenyResponse; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.EndPushToTalk; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.ExtendedFunctionCommand; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.ExtendedFunctionCommandExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.FrequencyBandUpdate; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.FrequencyBandUpdateTDMA; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.FrequencyBandUpdateVUHF; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupAffiliationQueryAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupAffiliationQueryExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupPagingMessage; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelGrantAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelGrantExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelGrantUpdate; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelGrantUpdateExplicit; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelGrantUpdateMultiple; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.GroupVoiceChannelGrantUpdateMultipleExplicit; +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.GroupVoiceServiceRequest; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.IndividualPagingMessage; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.MacRelease; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.MessageUpdateAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.MessageUpdateExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.NetworkStatusBroadcastAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.NetworkStatusBroadcastExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.NullInformationMessage; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.PowerControlSignalQuality; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.PushToTalk; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.QueuedResponse; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.RadioUnitMonitorCommand; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.RadioUnitMonitorCommandEnhanced; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.RadioUnitMonitorCommandExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.RfssStatusBroadcastAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.RfssStatusBroadcastExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.SNDCPDataChannelAnnouncementExplicit; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.SNDCPDataChannelGrant; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.SNDCPDataPageRequest; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.SecondaryControlChannelBroadcastAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.SecondaryControlChannelBroadcastExplicit; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.StatusQueryAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.StatusQueryExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.StatusUpdateAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.StatusUpdateExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.SystemServiceBroadcast; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.TelephoneInterconnectAnswerRequest; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.TelephoneInterconnectVoiceChannelUser; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitRegistrationCommandAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitAnswerRequestAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitAnswerRequestExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitVoiceChannelGrantAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitVoiceChannelGrantExtended; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitVoiceChannelGrantUpdateAbbreviated; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnitToUnitVoiceChannelGrantUpdateExtended; +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.message.mac.structure.UnknownStructure; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnknownVendorMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * Message factory for creating Encoded MAC Information (EMI) message parser instances. + */ +public class MacMessageFactory +{ + public static final int DEFAULT_MAC_STRUCTURE_INDEX = 8; + + private final static Logger mLog = LoggerFactory.getLogger(MacMessageFactory.class); + + public static List create(int timeslot, DataUnitID dataUnitID, + CorrectedBinaryMessage message, long timestamp) + { + List messages = new ArrayList<>(); + + MacPduType macPduType = MacMessage.getMacPduTypeFromMessage(message); + + switch(macPduType) + { + case MAC_0_RESERVED: + break; + case MAC_1_PTT: + messages.add(new MacMessage(timeslot, dataUnitID, message, timestamp, new PushToTalk(message))); + break; + case MAC_2_END_PTT: + messages.add(new MacMessage(timeslot, dataUnitID, message, timestamp, new EndPushToTalk(message))); + break; + case MAC_3_IDLE: + case MAC_4_ACTIVE: + case MAC_6_HANGTIME: + List indices = getMacStructureIndices(message); + + for(Integer index : indices) + { + MacStructure macStructure = createMacStructure(message, index); + messages.add(new MacMessage(timeslot, dataUnitID, message, timestamp, macStructure)); + } + break; + case MAC_5_RESERVED: + break; + case MAC_7_RESERVED: + break; + case MAC_UNKNOWN: + break; + default: + messages.add(new UnknownMacMessage(timeslot, dataUnitID, message, timestamp)); + break; + } + + return messages; + } + + /** + * Identifies the MAC structure start indices for the message + * + * @param message containing one or more MAC structures + * @return structure start indices + */ + private static List getMacStructureIndices(CorrectedBinaryMessage message) + { + List indices = new ArrayList<>(); + + //There should always be a MAC structure at index 8 + indices.add(DEFAULT_MAC_STRUCTURE_INDEX); + + MacOpcode opcode = MacStructure.getOpcode(message, DEFAULT_MAC_STRUCTURE_INDEX); + + int opcodeLength = opcode.getLength(); + + if(opcodeLength > 0 && opcode != MacOpcode.TDMA_0_NULL_INFORMATION_MESSAGE) + { + int secondStructureIndex = DEFAULT_MAC_STRUCTURE_INDEX + (opcode.getLength() * 8); + + if(secondStructureIndex < message.size()) + { + MacOpcode secondOpcode = MacStructure.getOpcode(message, secondStructureIndex); + + if(secondOpcode != MacOpcode.TDMA_0_NULL_INFORMATION_MESSAGE) + { + indices.add(secondStructureIndex); + + if(secondOpcode.getLength() > 0) + { + int thirdStructureIndex = secondStructureIndex + (secondOpcode.getLength() * 8); + + if(thirdStructureIndex < message.size()) + { + MacOpcode thirdOpcode = MacStructure.getOpcode(message, thirdStructureIndex); + + if(thirdOpcode != MacOpcode.TDMA_0_NULL_INFORMATION_MESSAGE) + { + indices.add(thirdStructureIndex); + } + } + } + } + } + } + + return indices; + } + + /** + * Creates a MAC structure parser for the message with the specified structure start offset. + * + * @param message containing a MAC structure + * @param offset to the start of the structure + * @return MAC structure parser + */ + public static MacStructure createMacStructure(CorrectedBinaryMessage message, int offset) + { + MacOpcode opcode = MacStructure.getOpcode(message, offset); + + switch(opcode) + { + case TDMA_0_NULL_INFORMATION_MESSAGE: + return new NullInformationMessage(message, offset); + case TDMA_1_GROUP_VOICE_CHANNEL_USER_ABBREVIATED: + return new GroupVoiceChannelUserAbbreviated(message, offset); + case TDMA_2_UNIT_TO_UNIT_VOICE_CHANNEL_USER: + return new UnitToUnitVoiceChannelUserAbbreviated(message, offset); + case TDMA_3_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER: + return new TelephoneInterconnectVoiceChannelUser(message, offset); + case TDMA_5_GROUP_VOICE_CHANNEL_GRANT_UPDATE_MULTIPLE: + return new GroupVoiceChannelGrantUpdateMultiple(message, offset); + case TDMA_17_INDIRECT_GROUP_PAGING: + return new GroupPagingMessage(message, offset); + case TDMA_18_INDIVIDUAL_PAGING_MESSAGE_WITH_PRIORITY: + return new IndividualPagingMessage(message, offset); + case TDMA_33_GROUP_VOICE_CHANNEL_USER_EXTENDED: + return new GroupVoiceChannelUserExtended(message, offset); + case TDMA_34_UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED: + return new UnitToUnitVoiceChannelUserExtended(message, offset); + case TDMA_37_GROUP_VOICE_CHANNEL_GRANT_UPDATE_MULTIPLE_EXPLICIT: + return new GroupVoiceChannelGrantUpdateMultipleExplicit(message, offset); + case TDMA_48_POWER_CONTROL_SIGNAL_QUALITY: + return new PowerControlSignalQuality(message, offset); + case TDMA_49_MAC_RELEASE: + return new MacRelease(message, offset); + case PHASE1_64_GROUP_VOICE_CHANNEL_GRANT_ABBREVIATED: + return new GroupVoiceChannelGrantAbbreviated(message, offset); + case PHASE1_65_GROUP_VOICE_SERVICE_REQUEST: + return new GroupVoiceServiceRequest(message, offset); + case PHASE1_66_GROUP_VOICE_CHANNEL_GRANT_UPDATE: + return new GroupVoiceChannelGrantUpdate(message, offset); + case PHASE1_68_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_ABBREVIATED: + return new UnitToUnitVoiceChannelGrantAbbreviated(message, offset); + case PHASE1_69_UNIT_TO_UNIT_ANSWER_REQUEST_ABBREVIATED: + return new UnitToUnitAnswerRequestAbbreviated(message, offset); + case PHASE1_70_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_ABBREVIATED: + return new UnitToUnitVoiceChannelGrantUpdateAbbreviated(message, offset); + case PHASE1_74_TELEPHONE_INTERCONNECT_ANSWER_REQUEST: + return new TelephoneInterconnectAnswerRequest(message, offset); + case PHASE1_76_RADIO_UNIT_MONITOR_COMMAND_ABBREVIATED: + return new RadioUnitMonitorCommand(message, offset); + case PHASE1_84_SNDCP_DATA_CHANNEL_GRANT: + return new SNDCPDataChannelGrant(message, offset); + case PHASE1_85_SNDCP_DATA_PAGE_REQUEST: + return new SNDCPDataPageRequest(message, offset); + case PHASE1_88_STATUS_UPDATE_ABBREVIATED: + return new StatusUpdateAbbreviated(message, offset); + case PHASE1_90_STATUS_QUERY_ABBREVIATED: + return new StatusQueryAbbreviated(message, offset); + case OBSOLETE_PHASE1_93_RADIO_UNIT_MONITOR_COMMAND: + return new UnknownStructure(message, offset); //Message is obsolete -- return unknown + case PHASE1_92_MESSAGE_UPDATE_ABBREVIATED: + return new MessageUpdateAbbreviated(message, offset); + case PHASE1_94_RADIO_UNIT_MONITOR_COMMAND_ENHANCED: + return new RadioUnitMonitorCommandEnhanced(message, offset); + case PHASE1_95_CALL_ALERT_ABBREVIATED: + return new CallAlertAbbreviated(message, offset); + case PHASE1_96_ACK_RESPONSE: + return new AcknowledgeResponse(message, offset); + case PHASE1_97_QUEUED_RESPONSE: + return new QueuedResponse(message, offset); + case PHASE1_100_EXTENDED_FUNCTION_COMMAND_ABBREVIATED: + return new ExtendedFunctionCommand(message, offset); + case PHASE1_103_DENY_RESPONSE: + return new DenyResponse(message, offset); + case PHASE1_106_GROUP_AFFILIATION_QUERY_ABBREVIATED: + return new GroupAffiliationQueryAbbreviated(message, offset); + case PHASE1_109_UNIT_REGISTRATION_COMMAND_ABBREVIATED: + return new UnitRegistrationCommandAbbreviated(message, offset); + case PHASE1_115_IDENTIFIER_UPDATE_TDMA: + return new FrequencyBandUpdateTDMA(message, offset); + case PHASE1_116_IDENTIFIER_UPDATE_V_UHF: + return new FrequencyBandUpdateVUHF(message, offset); + case PHASE1_117_TIME_AND_DATE_ANNOUNCEMENT: + return new DateAndTimeAnnouncement(message, offset); + case PHASE1_120_SYSTEM_SERVICE_BROADCAST: + return new SystemServiceBroadcast(message, offset); + case PHASE1_121_SECONDARY_CONTROL_CHANNEL_BROADCAST_ABBREVIATED: + return new SecondaryControlChannelBroadcastAbbreviated(message, offset); + case PHASE1_122_RFSS_STATUS_BROADCAST_ABBREVIATED: + return new RfssStatusBroadcastAbbreviated(message, offset); + case PHASE1_123_NETWORK_STATUS_BROADCAST_ABBREVIATED: + return new NetworkStatusBroadcastAbbreviated(message, offset); + case PHASE1_124_ADJACENT_STATUS_BROADCAST_ABBREVIATED: + return new AdjacentStatusBroadcastAbbreviated(message, offset); + case PHASE1_125_IDENTIFIER_UPDATE: + return new FrequencyBandUpdate(message, offset); + case PHASE1_192_GROUP_VOICE_CHANNEL_GRANT_EXTENDED: + return new GroupVoiceChannelGrantExtended(message, offset); + case PHASE1_195_GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT: + return new GroupVoiceChannelGrantUpdateExplicit(message, offset); + case PHASE1_196_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_EXTENDED: + return new UnitToUnitVoiceChannelGrantExtended(message, offset); + case PHASE1_197_UNIT_TO_UNIT_ANSWER_REQUEST_EXTENDED: + return new UnitToUnitAnswerRequestExtended(message, offset); + case PHASE1_198_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_EXTENDED: + return new UnitToUnitVoiceChannelGrantUpdateExtended(message, offset); + case PHASE1_204_RADIO_UNIT_MONITOR_COMMAND_EXTENDED: + return new RadioUnitMonitorCommandExtended(message, offset); + case PHASE1_214_SNDCP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT: + return new SNDCPDataChannelAnnouncementExplicit(message, offset); + case PHASE1_216_STATUS_UPDATE_EXTENDED: + return new StatusUpdateExtended(message, offset); + case PHASE1_218_STATUS_QUERY_EXTENDED: + return new StatusQueryExtended(message, offset); + case PHASE1_220_MESSAGE_UPDATE_EXTENDED: + return new MessageUpdateExtended(message, offset); + case PHASE1_223_CALL_ALERT_EXTENDED: + return new CallAlertExtended(message, offset); + case PHASE1_228_EXTENDED_FUNCTION_COMMAND_EXTENDED: + return new ExtendedFunctionCommandExtended(message, offset); + case PHASE1_233_SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT: + return new SecondaryControlChannelBroadcastExplicit(message, offset); + case PHASE1_234_GROUP_AFFILIATION_QUERY_EXTENDED: + return new GroupAffiliationQueryExtended(message, offset); + case PHASE1_250_RFSS_STATUS_BROADCAST_EXTENDED: + return new RfssStatusBroadcastExtended(message, offset); + case PHASE1_251_NETWORK_STATUS_BROADCAST_EXTENDED: + return new NetworkStatusBroadcastExtended(message, offset); + case PHASE1_252_ADJACENT_STATUS_BROADCAST_EXTENDED: + return new AdjacentStatusBroadcastExtended(message, offset); + + case VENDOR_PARTITION_2_UNKNOWN_OPCODE: + return new UnknownVendorMessage(message, offset); + } + + return new UnknownStructure(message, offset); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacOpcode.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacOpcode.java new file mode 100644 index 000000000..ca91fd617 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacOpcode.java @@ -0,0 +1,186 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac; + +import java.util.Map; +import java.util.TreeMap; + +/** + * MAC opcode is used with MAC_IDLE, MAC_ACTIVE and MAC_HANGTIME PDU format messages + */ +public enum MacOpcode +{ + PUSH_TO_TALK(-1, "PUSH-TO-TALK", -1), + END_PUSH_TO_TALK(-1, "END_PUSH-TO-TALK", -1), + + TDMA_0_NULL_INFORMATION_MESSAGE(0, "NULL INFORMATION", -1), + TDMA_1_GROUP_VOICE_CHANNEL_USER_ABBREVIATED(1, "GROUP VOICE CHANNEL USER ABBREVIATED", 7), + TDMA_2_UNIT_TO_UNIT_VOICE_CHANNEL_USER(2, "UNIT-TO-UNIT VOICE CHANNEL USER", 8), + TDMA_3_TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER(3, "TELEPHONE INTERCONNECT VOICE CHANNEL USER", 7), + TDMA_5_GROUP_VOICE_CHANNEL_GRANT_UPDATE_MULTIPLE(5, "GROUP VOICE CHANNEL GRANT UPDATE MULTIPLE", 16), + TDMA_17_INDIRECT_GROUP_PAGING(17, "INDIRECT GROUP PAGING", Integer.MIN_VALUE), + TDMA_18_INDIVIDUAL_PAGING_MESSAGE_WITH_PRIORITY(18, "INDIVIDUAL PAGING MESSAGE WITH PRIORITY", Integer.MIN_VALUE), + TDMA_33_GROUP_VOICE_CHANNEL_USER_EXTENDED(33, "GROUP VOICE CHANNEL USER EXTENDED", 14), + TDMA_34_UNIT_TO_UNIT_VOICE_CHANNEL_USER_EXTENDED(34, "UNIT-TO-UNIT VOICE CHANNEL USER EXTENDED", 15), + TDMA_37_GROUP_VOICE_CHANNEL_GRANT_UPDATE_MULTIPLE_EXPLICIT(37, "TDMA GROUP VOICE CHANNEL GRANT UPDATE EXPLICIT", 15), + TDMA_48_POWER_CONTROL_SIGNAL_QUALITY(48, "POWER CONTROL SIGNAL QUALITY", 5), + TDMA_49_MAC_RELEASE(49, "MAC RELEASE", 7), + TDMA_PARTITION_0_UNKNOWN_OPCODE(-1, "UNKNOWN TDMA OPCODE", -1), + + PHASE1_64_GROUP_VOICE_CHANNEL_GRANT_ABBREVIATED(64, "GROUP VOICE CHANNEL GRANT ABBREVIATED", 9), + PHASE1_65_GROUP_VOICE_SERVICE_REQUEST(65, "GROUP VOICE SERVICE REQUEST", 7), + PHASE1_66_GROUP_VOICE_CHANNEL_GRANT_UPDATE(66, "GROUP VOICE CHANNEL GRANT UPDATE", 9), + PHASE1_68_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_ABBREVIATED(68, "UNIT-TO-UNIT VOICE CHANNEL GRANT ABBREVIATED", 9), + PHASE1_69_UNIT_TO_UNIT_ANSWER_REQUEST_ABBREVIATED(69, "UNIT-TO-UNIT ANSWER REQUEST ABBREVIATED", 8), + PHASE1_70_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_ABBREVIATED(70, "UNIT-TO-UNIT VOICE CHANNEL GRANT UPDATE ABBREVIATED", 9), + PHASE1_74_TELEPHONE_INTERCONNECT_ANSWER_REQUEST(74, "TELEPHONE INTERCONNECT_ANSWER REQUEST", 9), + PHASE1_76_RADIO_UNIT_MONITOR_COMMAND_ABBREVIATED(76, "RADIO UNIT MONITOR COMMAND ABBREVIATED", 10), + PHASE1_84_SNDCP_DATA_CHANNEL_GRANT(84, "SNDCP DATA CHANNEL GRANT", 9), + PHASE1_85_SNDCP_DATA_PAGE_REQUEST(85, "SNDCP DATA PAGE REQUEST", 7), + PHASE1_88_STATUS_UPDATE_ABBREVIATED(88, "STATUS UPDATE ABBREVIATED", 10), + PHASE1_90_STATUS_QUERY_ABBREVIATED(90, "STATUS QUERY ABBREVIATED", 7), + PHASE1_92_MESSAGE_UPDATE_ABBREVIATED(92, "MESSAGE UPDATE ABBREVIATED", 10), + OBSOLETE_PHASE1_93_RADIO_UNIT_MONITOR_COMMAND(93, "RADIO UNIT MONITOR COMMAND", 8), + PHASE1_94_RADIO_UNIT_MONITOR_COMMAND_ENHANCED(94, "RADIO UNIT MONITOR ENHANCED COMMAND ABBREVIATED", 14), + PHASE1_95_CALL_ALERT_ABBREVIATED(95, "CALL ALERT ABBREVIATED", 7), + PHASE1_96_ACK_RESPONSE(96, "ACK RESPONSE", 9), + PHASE1_97_QUEUED_RESPONSE(97, "QUEUED RESPONSE", 9), + PHASE1_100_EXTENDED_FUNCTION_COMMAND_ABBREVIATED(100, "EXTENDED FUNCTION COMMAND ABBREVIATED", 9), + PHASE1_103_DENY_RESPONSE(103, "DENY RESPONSE", 9), + PHASE1_106_GROUP_AFFILIATION_QUERY_ABBREVIATED(106, "GROUP AFFILIATION QUERY ABBREVIATED", 7), + PHASE1_109_UNIT_REGISTRATION_COMMAND_ABBREVIATED(109, "UNIT REGISTRATION COMMAND ABBREVIATED", 7), + PHASE1_115_IDENTIFIER_UPDATE_TDMA(115, "IDENTIFIER UPDATE TDMA", 9), + PHASE1_116_IDENTIFIER_UPDATE_V_UHF(116, "IDENTIFIER UPDATE V/UHF", 9), + PHASE1_117_TIME_AND_DATE_ANNOUNCEMENT(117, "TIME AND DATE ANNOUNCEMENT", 9), + PHASE1_120_SYSTEM_SERVICE_BROADCAST(120, "SYSTEM SERVICE BROADCAST", 9), + PHASE1_121_SECONDARY_CONTROL_CHANNEL_BROADCAST_ABBREVIATED(121, "SECONDARY CONTROL CHANNEL BROADCAST", 9), + PHASE1_122_RFSS_STATUS_BROADCAST_ABBREVIATED(122, "RFSS STATUS BROADCAST ABBREVIATED", 9), + PHASE1_123_NETWORK_STATUS_BROADCAST_ABBREVIATED(123, "NETWORK STATUS BROADCAST ABBREVIATED", 11), + PHASE1_124_ADJACENT_STATUS_BROADCAST_ABBREVIATED(124, "ADJACENT STATUS BROADCAST ABBREVIATED", 9), + PHASE1_125_IDENTIFIER_UPDATE(125, "IDENTIFIER UPDATE", 9), + PHASE1_PARTITION_1_UNKNOWN_OPCODE(-1, "UNKNOWN PHASE 1 OPCODE", -1), + + VENDOR_PARTITION_2_UNKNOWN_OPCODE(-1, "UNKNOWN VENDOR OPCODE", -1), + + PHASE1_192_GROUP_VOICE_CHANNEL_GRANT_EXTENDED(192, "GROUP VOICE CHANNEL GRANT EXTENDED", 11), + PHASE1_195_GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT(195, "GROUP VOICE CHANNEL GRANT UPDATE EXPLICIT", 8), + PHASE1_196_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_EXTENDED(196, "UNIT-TO-UNIT VOICE CHANNEL GRANT ABBREVIATED", 15), + PHASE1_197_UNIT_TO_UNIT_ANSWER_REQUEST_EXTENDED(197, "UNIT-TO-UNIT ANSWER REQUEST EXTENDED", 12), + PHASE1_198_UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE_EXTENDED(198, "UNIT-TO-UNIT VOICE CHANNEL GRANT EXTENDED", 15), + PHASE1_204_RADIO_UNIT_MONITOR_COMMAND_EXTENDED(204, "RADIO UNIT MONITOR COMMAND EXTENDED", 14), + PHASE1_214_SNDCP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT(214, "SNDCP DATA CHANNEL ANNOUNCEMENT EXPLICIT", 9), + PHASE1_216_STATUS_UPDATE_EXTENDED(216, "STATUS UPDATE EXTENDED", 14), + PHASE1_218_STATUS_QUERY_EXTENDED(218, "STATUS QUERY EXTENDED", 11), + PHASE1_220_MESSAGE_UPDATE_EXTENDED(220, "MESSAGE UPDATE EXTENDED", 14), + PHASE1_223_CALL_ALERT_EXTENDED(223, "CALL ALERT EXTENDED", 11), + PHASE1_228_EXTENDED_FUNCTION_COMMAND_EXTENDED(228, "EXTENDED FUNCTION COMMAND EXTENDED", 14), + PHASE1_233_SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT(233, "SECONDARY CONTROL CHANNEL BROADCAST EXPLICIT", 8), + PHASE1_234_GROUP_AFFILIATION_QUERY_EXTENDED(234, "GROUP AFFILIATION QUERY EXTENDED", 11), + PHASE1_250_RFSS_STATUS_BROADCAST_EXTENDED(250, "RFSS STATUS BROADCAST EXTENDED", 11), + PHASE1_251_NETWORK_STATUS_BROADCAST_EXTENDED(251, "NETWORK STATUS BROADCAST EXTENDED", 13), + PHASE1_252_ADJACENT_STATUS_BROADCAST_EXTENDED(252, "ADJACENT STATUS BROADCAST EXTENDED", 11), + PHASE1_EXTENDED_PARTITION_3_UNKNOWN_OPCODE(-1, "UNKNOWN EXTENDED PHASE 1 OPCODE", 1), + + UNKNOWN(-1, "UNKNOWN", -1); + + private static final Map LOOKUP_MAP = new TreeMap<>(); + + static + { + for(MacOpcode macOpcode : MacOpcode.values()) + { + if(macOpcode.getValue() != -1) + { + LOOKUP_MAP.put(macOpcode.getValue(), macOpcode); + } + } + } + + private int mValue; + private String mLabel; + private int mLength; + + MacOpcode(int value, String label, int length) + { + mValue = value; + mLabel = label; + mLength = length; + } + + @Override + public String toString() + { + return mLabel; + } + + public int getValue() + { + return mValue; + } + + /** + * Length of the message in octets/bytes for the opcode + */ + public int getLength() + { + return mLength; + } + + /** + * Indicates if the opcode is for a variable-length message + */ + public boolean isVariableLength() + { + return getLength() == Integer.MIN_VALUE; + } + + /** + * Lookup the MAC opcode from an integer value + */ + public static MacOpcode fromValue(int value) + { + if(LOOKUP_MAP.containsKey(value)) + { + return LOOKUP_MAP.get(value); + } + + if(0 <= value && value <= 63) + { + return TDMA_PARTITION_0_UNKNOWN_OPCODE; + } + else if(64 <= value && value <= 127) + { + return PHASE1_PARTITION_1_UNKNOWN_OPCODE; + } + else if(128 <= value && value <= 191) + { + return VENDOR_PARTITION_2_UNKNOWN_OPCODE; + } + else if(192 <= value && value <= 255) + { + return PHASE1_EXTENDED_PARTITION_3_UNKNOWN_OPCODE; + } + + return UNKNOWN; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacPduType.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacPduType.java new file mode 100644 index 000000000..5e63c662a --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacPduType.java @@ -0,0 +1,62 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac; + +/** + * MAC opcode is used to convey the type of MAC PDU for a MAC message + */ +public enum MacPduType +{ + MAC_0_RESERVED("RESERVED-0"), + MAC_1_PTT("PUSH-TO-TALK"), + MAC_2_END_PTT("END PUSH-TO-TALK"), + MAC_3_IDLE("IDLE"), + MAC_4_ACTIVE("ACTIVE"), + MAC_5_RESERVED("RESERVED-5"), + MAC_6_HANGTIME("HANGTIME"), + MAC_7_RESERVED("RESERVED-7"), + MAC_UNKNOWN("UNKNOWN"); + + private String mLabel; + + MacPduType(String label) + { + mLabel = label; + } + + @Override + public String toString() + { + return mLabel; + } + + public static MacPduType fromValue(int value) + { + if(0 <= value && value <= 7) + { + return MacPduType.values()[value]; + } + + return MAC_UNKNOWN; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacStructure.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacStructure.java new file mode 100644 index 000000000..c2751dd29 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/MacStructure.java @@ -0,0 +1,114 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; + +import java.util.List; + +/** + * Structure parsing parent class for MAC message payload structures. + */ +public abstract class MacStructure +{ + private static int[] OPCODE = {0, 1, 2, 3, 4, 5, 6, 7}; + + private CorrectedBinaryMessage mMessage; + private int mOffset; + + /** + * Constructs a MAC structure parser + * + * @param message containing a MAC structure + * @param offset in the message to the start of the structure + */ + protected MacStructure(CorrectedBinaryMessage message, int offset) + { + mMessage = message; + mOffset = offset; + } + + /** + * List of identifiers provided by this structure + */ + public abstract List getIdentifiers(); + + /** + * Underlying binary message. + * + * @return message + */ + protected CorrectedBinaryMessage getMessage() + { + return mMessage; + } + + /** + * Offset to the start of the structure in the underlying binary message + * + * @return offset + */ + protected int getOffset() + { + return mOffset; + } + + /** + * Opcode for the message argument + * @param message containing a mac opcode message + * @param offset into the message + * @return opcode + */ + public static MacOpcode getOpcode(CorrectedBinaryMessage message, int offset) + { + return MacOpcode.fromValue(message.getInt(OPCODE, offset)); + } + + /** + * Numeric value of the opcode + * @param message containing a mac opcode message + * @param offset into the message to the start of the mac sequence + * @return integer value + */ + public static int getOpcodeNumber(CorrectedBinaryMessage message, int offset) + { + return message.getInt(OPCODE, offset); + } + + /** + * Opcode for this message + */ + public MacOpcode getOpcode() + { + return getOpcode(getMessage(), getOffset()); + } + + /** + * Opcode numeric value for this structure + */ + public int getOpcodeNumber() + { + return getOpcodeNumber(getMessage(), getOffset()); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/UnknownMacMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/UnknownMacMessage.java new file mode 100644 index 000000000..77fdf791a --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/UnknownMacMessage.java @@ -0,0 +1,74 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.UnknownStructure; + +import java.util.Collections; +import java.util.List; + +/** + * Unknown MAC Message. + */ +public class UnknownMacMessage extends MacMessage +{ + + /** + * Constructs the message + * + * @param message containing the message bits + * @param timestamp of the final bit of the message + */ + public UnknownMacMessage(int timeslot, DataUnitID dataUnitID, CorrectedBinaryMessage message, long timestamp) + { + super(timeslot, dataUnitID, message, timestamp, new UnknownStructure(message, 0)); + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append("TS").append(getTimeslot()); + sb.append(" ").append(getDataUnitID()); + + if(isValid()) + { + sb.append(" ").append(getMacStructure().toString()); + } + else + { + sb.append(" INVALID/CRC ERROR"); + } + + return sb.toString(); + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/AcknowledgeResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/AcknowledgeResponse.java new file mode 100644 index 000000000..6aecf91a9 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/AcknowledgeResponse.java @@ -0,0 +1,193 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Wacn; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacOpcode; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Acknowledge response + */ +public class AcknowledgeResponse extends MacStructure +{ + private static final int ADDITIONAL_INFORMATION_INDICATOR = 8; + private static final int EXTENDED_ADDRESS = 9; + private static final int[] SERVICE_TYPE = {10, 11, 12, 13, 14, 15}; + + private static final int[] TARGET_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[] TARGET_SYSTEM = {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 int[] SOURCE_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 List mIdentifiers; + + private TalkgroupIdentifier mTargetAddress; + private Identifier mTargetWacn; + private Identifier mTargetSystem; + private TalkgroupIdentifier mSourceAddress; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public AcknowledgeResponse(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + + if(hasAdditionalInformation()) + { + if(hasExtendedAddressing()) + { + sb.append(" WACN:").append(getTargetWacn()); + sb.append(" SYS:").append(getTargetSystem()); + } + else + { + sb.append(" FM:").append(getSourceAddress()); + } + } + + sb.append(" ACKNOWLEDGING:").append(getServiceType().toString()); + + return sb.toString(); + } + + /** + * Indicates if this message contains additional information fields. + */ + public boolean hasAdditionalInformation() + { + return getMessage().get(ADDITIONAL_INFORMATION_INDICATOR + getOffset()); + } + + /** + * Indicates if this message has extended addressing + */ + public boolean hasExtendedAddressing() + { + return getMessage().get(EXTENDED_ADDRESS + getOffset()); + } + + /** + * The service type opcode associated with the acknowledgment + */ + public MacOpcode getServiceType() + { + return MacOpcode.fromValue(getMessage().getInt(SERVICE_TYPE, getOffset())); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + public Identifier getTargetWacn() + { + if(hasAdditionalInformation() && hasExtendedAddressing() && mTargetWacn == null) + { + mTargetWacn = APCO25Wacn.create(getMessage().getInt(TARGET_WACN, getOffset())); + } + + return mTargetWacn; + } + + public Identifier getTargetSystem() + { + if(hasAdditionalInformation() && hasExtendedAddressing() && mTargetSystem == null) + { + mTargetSystem = APCO25Wacn.create(getMessage().getInt(TARGET_SYSTEM, getOffset())); + } + + return mTargetSystem; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(hasAdditionalInformation() && !hasExtendedAddressing() && mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + + if(hasAdditionalInformation()) + { + if(hasExtendedAddressing()) + { + mIdentifiers.add(getTargetWacn()); + mIdentifiers.add(getTargetSystem()); + } + else + { + mIdentifiers.add(getSourceAddress()); + } + } + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/AdjacentStatusBroadcastAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/AdjacentStatusBroadcastAbbreviated.java new file mode 100644 index 000000000..0207c6fc7 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/AdjacentStatusBroadcastAbbreviated.java @@ -0,0 +1,240 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; +import io.github.dsheirer.module.decode.p25.identifier.APCO25System; +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.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Adjacent (neighbor site) status broadcast - abbreviated format + */ +public class AdjacentStatusBroadcastAbbreviated extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] LRA = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int CONVENTIONAL_CHANNEL_FLAG = 16; + private static final int SITE_FAILURE_FLAG = 17; + private static final int VALID_INFORMATION_FLAG = 18; + private static final int ACTIVE_NETWORK_CONNECTION_TO_RFSS_CONTROLLER_FLAG = 19; + private static final int[] SYSTEM_ID = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + + private static final int[] RFSS_ID = {32, 33, 34, 35, 36, 37, 38, 39}; + private static final int[] SITE_ID = {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 List mIdentifiers; + private Identifier mLRA; + private List mSiteFlags; + private Identifier mSystem; + private Identifier mRFSS; + private Identifier mSite; + private APCO25Channel mChannel; + private SystemServiceClass mSystemServiceClass; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public AdjacentStatusBroadcastAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" SYSTEM:").append(getSystem()); + sb.append(" RFSS:").append(getRFSS()); + sb.append(" SITE:").append(getSite()); + sb.append(" LRA:").append(getLRA()); + sb.append(" CHANNEL:").append(getChannel()); + sb.append(" FLAGS:").append(getSiteFlags()); + sb.append(" SERVICES:").append(getSystemServiceClass().getServices()); + return sb.toString(); + } + + public Identifier getLRA() + { + if(mLRA == null) + { + mLRA = APCO25Lra.create(getMessage().getInt(LRA, getOffset())); + } + + return mLRA; + } + + public List getSiteFlags() + { + if(mSiteFlags == null) + { + mSiteFlags = new ArrayList<>(); + + if(isConventionalChannel()) + { + mSiteFlags.add("CONVENTIONAL CHANNEL"); + } + + if(isFailedConditionSite()) + { + mSiteFlags.add("FAILURE CONDITION"); + } + + if(isValidSiteInformation()) + { + mSiteFlags.add("VALID INFORMATION"); + } + + if(isActiveNetworkConnectionToRfssControllerSite()) + { + mSiteFlags.add("ACTIVE RFSS CONNECTION"); + } + } + + return mSiteFlags; + } + + /** + * Indicates if the channel is a conventional repeater channel + */ + public boolean isConventionalChannel() + { + return getMessage().get(CONVENTIONAL_CHANNEL_FLAG + getOffset()); + } + + /** + * Indicates if the site is in a failure condition + */ + public boolean isFailedConditionSite() + { + return getMessage().get(SITE_FAILURE_FLAG + getOffset()); + } + + /** + * Indicates if the site informaiton is valid + */ + public boolean isValidSiteInformation() + { + return getMessage().get(VALID_INFORMATION_FLAG + getOffset()); + } + + /** + * Indicates if the site has an active network connection to the RFSS controller + */ + public boolean isActiveNetworkConnectionToRfssControllerSite() + { + return getMessage().get(ACTIVE_NETWORK_CONNECTION_TO_RFSS_CONTROLLER_FLAG + getOffset()); + } + + public Identifier getRFSS() + { + if(mRFSS == null) + { + mRFSS = APCO25Rfss.create(getMessage().getInt(RFSS_ID, getOffset())); + } + + return mRFSS; + } + + public Identifier getSite() + { + if(mSite == null) + { + mSite = APCO25Site.create(getMessage().getInt(SITE_ID, getOffset())); + } + + return mSite; + } + + public Identifier getSystem() + { + if(mSystem == null) + { + mSystem = APCO25System.create(getMessage().getInt(SYSTEM_ID, getOffset())); + } + + return mSystem; + } + + public APCO25Channel getChannel() + { + if(mChannel == null) + { + mChannel = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND, getOffset()), + getMessage().getInt(CHANNEL_NUMBER, getOffset())); + } + + return mChannel; + } + + public SystemServiceClass getSystemServiceClass() + { + if(mSystemServiceClass == null) + { + mSystemServiceClass = SystemServiceClass.create(getMessage().getInt(SERVICE_CLASS, getOffset())); + } + + return mSystemServiceClass; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getLRA()); + mIdentifiers.add(getSystem()); + mIdentifiers.add(getRFSS()); + mIdentifiers.add(getSite()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + return Collections.singletonList(getChannel()); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/AdjacentStatusBroadcastExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/AdjacentStatusBroadcastExtended.java new file mode 100644 index 000000000..844daff39 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/AdjacentStatusBroadcastExtended.java @@ -0,0 +1,245 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; +import io.github.dsheirer.module.decode.p25.identifier.APCO25System; +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.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Adjacent (neighbor site) status broadcast - abbreviated format + */ +public class AdjacentStatusBroadcastExtended extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] LRA = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int CONVENTIONAL_CHANNEL_FLAG = 16; + private static final int SITE_FAILURE_FLAG = 17; + private static final int VALID_INFORMATION_FLAG = 18; + private static final int ACTIVE_NETWORK_CONNECTION_TO_RFSS_CONTROLLER_FLAG = 19; + private static final int[] SYSTEM_ID = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + + private static final int[] RFSS_ID = {32, 33, 34, 35, 36, 37, 38, 39}; + private static final int[] SITE_ID = {40, 41, 42, 43, 44, 45, 46, 47}; + private static final int[] TRANSMIT_FREQUENCY_BAND = {48, 49, 50, 51}; + private static final int[] TRANSMIT_CHANNEL_NUMBER = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; + private static final int[] RECEIVE_FREQUENCY_BAND = {64, 65, 66, 67}; + private static final int[] RECEIVE_CHANNEL_NUMBER = {68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}; + private static final int[] SERVICE_CLASS = {80, 81, 82, 83, 84, 85, 86, 87}; + + private List mIdentifiers; + private Identifier mLRA; + private List mSiteFlags; + private Identifier mSystem; + private Identifier mRFSS; + private Identifier mSite; + private APCO25Channel mChannel; + private SystemServiceClass mSystemServiceClass; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public AdjacentStatusBroadcastExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" SYSTEM:").append(getSystem()); + sb.append(" RFSS:").append(getRFSS()); + sb.append(" SITE:").append(getSite()); + sb.append(" LRA:").append(getLRA()); + sb.append(" CHANNEL:").append(getChannel()); + sb.append(" FLAGS:").append(getSiteFlags()); + sb.append(" SERVICES:").append(getSystemServiceClass().getServices()); + return sb.toString(); + } + + public Identifier getLRA() + { + if(mLRA == null) + { + mLRA = APCO25Lra.create(getMessage().getInt(LRA, getOffset())); + } + + return mLRA; + } + + public List getSiteFlags() + { + if(mSiteFlags == null) + { + mSiteFlags = new ArrayList<>(); + + if(isConventionalChannel()) + { + mSiteFlags.add("CONVENTIONAL CHANNEL"); + } + + if(isFailedConditionSite()) + { + mSiteFlags.add("FAILURE CONDITION"); + } + + if(isValidSiteInformation()) + { + mSiteFlags.add("VALID INFORMATION"); + } + + if(isActiveNetworkConnectionToRfssControllerSite()) + { + mSiteFlags.add("ACTIVE RFSS CONNECTION"); + } + } + + return mSiteFlags; + } + + /** + * Indicates if the channel is a conventional repeater channel + */ + public boolean isConventionalChannel() + { + return getMessage().get(CONVENTIONAL_CHANNEL_FLAG + getOffset()); + } + + /** + * Indicates if the site is in a failure condition + */ + public boolean isFailedConditionSite() + { + return getMessage().get(SITE_FAILURE_FLAG + getOffset()); + } + + /** + * Indicates if the site informaiton is valid + */ + public boolean isValidSiteInformation() + { + return getMessage().get(VALID_INFORMATION_FLAG + getOffset()); + } + + /** + * Indicates if the site has an active network connection to the RFSS controller + */ + public boolean isActiveNetworkConnectionToRfssControllerSite() + { + return getMessage().get(ACTIVE_NETWORK_CONNECTION_TO_RFSS_CONTROLLER_FLAG + getOffset()); + } + + public Identifier getRFSS() + { + if(mRFSS == null) + { + mRFSS = APCO25Rfss.create(getMessage().getInt(RFSS_ID, getOffset())); + } + + return mRFSS; + } + + public Identifier getSite() + { + if(mSite == null) + { + mSite = APCO25Site.create(getMessage().getInt(SITE_ID, getOffset())); + } + + return mSite; + } + + public Identifier getSystem() + { + if(mSystem == null) + { + mSystem = APCO25System.create(getMessage().getInt(SYSTEM_ID, getOffset())); + } + + return mSystem; + } + + public APCO25Channel getChannel() + { + if(mChannel == null) + { + mChannel = APCO25ExplicitChannel.create(getMessage().getInt(TRANSMIT_FREQUENCY_BAND, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER, getOffset()), + getMessage().getInt(RECEIVE_FREQUENCY_BAND, getOffset()), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER, getOffset())); + } + + return mChannel; + } + + public SystemServiceClass getSystemServiceClass() + { + if(mSystemServiceClass == null) + { + mSystemServiceClass = SystemServiceClass.create(getMessage().getInt(SERVICE_CLASS, getOffset())); + } + + return mSystemServiceClass; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getLRA()); + mIdentifiers.add(getSystem()); + mIdentifiers.add(getRFSS()); + mIdentifiers.add(getSite()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + return Collections.singletonList(getChannel()); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/CallAlertAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/CallAlertAbbreviated.java new file mode 100644 index 000000000..3ec80e162 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/CallAlertAbbreviated.java @@ -0,0 +1,110 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Call alert - abbreviated format + */ +public class CallAlertAbbreviated extends MacStructure +{ + private static final int[] TARGET_ADDRESS = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31}; + private static final int[] SOURCE_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private TalkgroupIdentifier mSourceAddress; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public CallAlertAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceAddress()); + return sb.toString(); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/CallAlertExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/CallAlertExtended.java new file mode 100644 index 000000000..044645fbd --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/CallAlertExtended.java @@ -0,0 +1,114 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FullyQualifiedIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Call alert - extended format + */ +public class CallAlertExtended extends MacStructure +{ + private static final int[] TARGET_ADDRESS = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31}; + private static final int[] SOURCE_WACN = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51}; + private static final int[] SOURCE_SYSTEM = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; + private static final int[] SOURCE_ADDRESS = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private APCO25FullyQualifiedIdentifier mSourceSuid; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public CallAlertExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceSuid()); + return sb.toString(); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public APCO25FullyQualifiedIdentifier getSourceSuid() + { + if(mSourceSuid == null) + { + mSourceSuid = APCO25FullyQualifiedIdentifier.createFrom(getMessage().getInt(SOURCE_WACN, getOffset()), + getMessage().getInt(SOURCE_SYSTEM, getOffset()), getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceSuid; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceSuid()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/DateAndTimeAnnouncement.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/DateAndTimeAnnouncement.java new file mode 100644 index 000000000..d0c02274d --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/DateAndTimeAnnouncement.java @@ -0,0 +1,76 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.Collections; +import java.util.List; + +/** + * Date and time announcement + * + * NOTE: no ICD - parser is incomplete + */ +public class DateAndTimeAnnouncement extends MacStructure +{ + private static final int VD_FLAG = 8; + private static final int VT_FLAG = 9; + private static final int VL_FLAG = 10; + private static final int[] LOCAL_TIME_OFFSET = {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] DATE = {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[] TIME = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71}; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public DateAndTimeAnnouncement(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" DATE:").append(getMessage().getInt(DATE, getOffset())); + sb.append(" TIME:").append(getMessage().getInt(TIME, getOffset())); + return sb.toString(); + } + + @Override + public List getIdentifiers() + { + return Collections.emptyList(); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/DenyResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/DenyResponse.java new file mode 100644 index 000000000..46262c840 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/DenyResponse.java @@ -0,0 +1,138 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacOpcode; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.DenyReason; + +import java.util.ArrayList; +import java.util.List; + +/** + * Deny response + */ +public class DenyResponse extends MacStructure +{ + private static final int ADDITIONAL_INFORMATION_INDICATOR = 8; + private static final int[] SERVICE_TYPE = {10, 11, 12, 13, 14, 15}; + private static final int[] REASON = {24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] ADDITIONAL_INFO = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + private static final int[] TARGET_ADDRESS = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79}; + + private DenyReason mDenyReason; + private String mAdditionalInfo; + private Identifier mTargetAddress; + private List mIdentifiers; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public DenyResponse(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" SERVICE:").append(getDeniedServiceType()); + sb.append(" REASON:").append(getDenyReason()); + + if(hasAdditionalInformation()) + { + sb.append(" INFO:").append(getAdditionalInfo()); + } + + return sb.toString(); + } + + private boolean hasAdditionalInformation() + { + return getMessage().get(ADDITIONAL_INFORMATION_INDICATOR + getOffset()); + } + + public String getAdditionalInfo() + { + if(mAdditionalInfo == null) + { + int arguments = getMessage().getInt(ADDITIONAL_INFO, getOffset()); + mAdditionalInfo = Integer.toHexString(arguments).toUpperCase(); + } + + return mAdditionalInfo; + } + + /** + * Opcode representing the service type that is being acknowledged by the radio unit. + */ + public MacOpcode getDeniedServiceType() + { + return MacOpcode.fromValue(getMessage().getInt(SERVICE_TYPE, getOffset())); + } + + public DenyReason getDenyReason() + { + if(mDenyReason == null) + { + mDenyReason = DenyReason.fromCode(getMessage().getInt(REASON, getOffset())); + } + + return mDenyReason; + } + + public Identifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/EndPushToTalk.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/EndPushToTalk.java new file mode 100644 index 000000000..924d8010f --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/EndPushToTalk.java @@ -0,0 +1,139 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Nac; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacOpcode; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Call end. + * + * Similar to a P25 Phase 1 Terminator Data Unit (TDU). + */ +public class EndPushToTalk extends MacStructure +{ + private static final int SYSTEM_CONTROLLER = 16777215; + private static int[] COLOR_CODE = {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + private static int[] SOURCE_ADDRESS = {104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127}; + private static int[] GROUP_ADDRESS = {128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143}; + + private Identifier mColorCode; + private TalkgroupIdentifier mSourceAddress; + private TalkgroupIdentifier mGroupAddress; + private List mIdentifiers; + + /** + * Constructs the message + * + * @param message containing the message bits + */ + public EndPushToTalk(CorrectedBinaryMessage message) + { + super(message, 0); + } + + @Override + public MacOpcode getOpcode() + { + return MacOpcode.END_PUSH_TO_TALK; + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append("FROM:").append(getSourceAddress()); + sb.append(" TO:").append(getGroupAddress()); + sb.append(" NAC:").append(getNAC()); + + return sb.toString(); + } + + /** + * NAC or Color Code + */ + public Identifier getNAC() + { + if(mColorCode == null) + { + mColorCode = APCO25Nac.create(getMessage().getInt(COLOR_CODE, getOffset())); + } + + return mColorCode; + } + + /** + * Calling (source) radio identifier + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + /** + * Called (destination) group identifier + */ + public TalkgroupIdentifier getGroupAddress() + { + if(mGroupAddress == null) + { + mGroupAddress = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS, getOffset())); + } + + return mGroupAddress; + } + + /** + * List of identifiers contained in this message + */ + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getSourceAddress()); + mIdentifiers.add(getGroupAddress()); + mIdentifiers.add(getNAC()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/ExtendedFunctionCommand.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/ExtendedFunctionCommand.java new file mode 100644 index 000000000..7d7a93546 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/ExtendedFunctionCommand.java @@ -0,0 +1,120 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.ExtendedFunction; + +import java.util.ArrayList; +import java.util.List; + +/** + * Extended function command + */ +public class ExtendedFunctionCommand extends MacStructure +{ + private static final int[] FUNCTION = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] 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 ExtendedFunction mExtendedFunction; + private String mArguments; + private TalkgroupIdentifier mTargetAddress; + private List mIdentifiers; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public ExtendedFunctionCommand(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FUNCTION:").append(getExtendedFunction()); + sb.append(" ARGUMENTS:").append(getArguments()); + return sb.toString(); + } + + public ExtendedFunction getExtendedFunction() + { + if(mExtendedFunction == null) + { + mExtendedFunction = ExtendedFunction.fromValue(getMessage().getInt(FUNCTION, getOffset())); + } + + return mExtendedFunction; + } + + public String getArguments() + { + if(mArguments == null) + { + int arguments = getMessage().getInt(ARGUMENTS, getOffset()); + mArguments = Integer.toHexString(arguments).toUpperCase(); + } + + return mArguments; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/ExtendedFunctionCommandExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/ExtendedFunctionCommandExtended.java new file mode 100644 index 000000000..c8fbb96cb --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/ExtendedFunctionCommandExtended.java @@ -0,0 +1,143 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FullyQualifiedIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.ExtendedFunction; + +import java.util.ArrayList; +import java.util.List; + +/** + * Extended function command - extended format + */ +public class ExtendedFunctionCommandExtended extends MacStructure +{ + private static final int[] FUNCTION = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] ARGUMENTS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55}; + private static final int[] TARGET_ADDRESS = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79}; + private static final int[] FULLY_QUALIFIED_SOURCE_WACN = {80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99}; + private static final int[] FULLY_QUALIFIED_SOURCE_SYSTEM = {100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111}; + private static final int[] FULLY_QUALIFIED_SOURCE_ID = {112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135}; + + private ExtendedFunction mExtendedFunction; + private String mArguments; + private TalkgroupIdentifier mTargetAddress; + private APCO25FullyQualifiedIdentifier mSourceSuid; + private List mIdentifiers; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public ExtendedFunctionCommandExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceSuid()); + sb.append(" FUNCTION:").append(getExtendedFunction()); + sb.append(" ARGUMENTS:").append(getArguments()); + return sb.toString(); + } + + public ExtendedFunction getExtendedFunction() + { + if(mExtendedFunction == null) + { + mExtendedFunction = ExtendedFunction.fromValue(getMessage().getInt(FUNCTION, getOffset())); + } + + return mExtendedFunction; + } + + public String getArguments() + { + if(mArguments == null) + { + int arguments = getMessage().getInt(ARGUMENTS, getOffset()); + mArguments = Integer.toHexString(arguments).toUpperCase(); + } + + return mArguments; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + public APCO25FullyQualifiedIdentifier getSourceSuid() + { + if(mSourceSuid == null) + { + int wacn = getMessage().getInt(FULLY_QUALIFIED_SOURCE_WACN, getOffset()); + int system = getMessage().getInt(FULLY_QUALIFIED_SOURCE_SYSTEM, getOffset()); + int id = getMessage().getInt(FULLY_QUALIFIED_SOURCE_ID, getOffset()); + + mSourceSuid = APCO25FullyQualifiedIdentifier.createFrom(wacn, system, id); + } + + return mSourceSuid; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceSuid()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/FrequencyBandUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/FrequencyBandUpdate.java new file mode 100644 index 000000000..34b0ee3a4 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/FrequencyBandUpdate.java @@ -0,0 +1,151 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.Collections; +import java.util.List; + +/** + * Identifier update (frequency band) + */ +public class FrequencyBandUpdate extends MacStructure 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 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}; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public FrequencyBandUpdate(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" ID:").append(getIdentifier()); + sb.append(" OFFSET:").append(getTransmitOffset()); + sb.append(" SPACING:").append(getChannelSpacing()); + sb.append(" BASE:").append(getBaseFrequency()); + sb.append(" FDMA BW:").append(getBandwidth()); + return sb.toString(); + } + + @Override + public int getIdentifier() + { + return getMessage().getInt(FREQUENCY_BAND_IDENTIFIER); + } + + @Override + public long getChannelSpacing() + { + return getMessage().getInt(CHANNEL_SPACING, getOffset()) * 125; + } + + @Override + public long getBaseFrequency() + { + return getMessage().getLong(BASE_FREQUENCY, getOffset()) * 5; + } + + @Override + public int getBandwidth() + { + return getMessage().getInt(BANDWIDTH, getOffset()) * 125; + } + + @Override + public long getTransmitOffset() + { + long offset = getMessage().getLong(TRANSMIT_OFFSET, getOffset()) * getChannelSpacing(); + + if(!getMessage().get(TRANSMIT_OFFSET_SIGN + getOffset())) + { + offset *= -1; + } + + return offset; + } + + /** + * Indicates if the frequency band has a transmit option for the subscriber unit. + */ + public boolean hasTransmitOffset() + { + return getMessage().getInt(TRANSMIT_OFFSET, getOffset()) != 0x80; + } + + @Override + public long getDownlinkFrequency(int channelNumber) + { + return getBaseFrequency() + (getChannelSpacing() * channelNumber); + } + + @Override + public long getUplinkFrequency(int channelNumber) + { + if(hasTransmitOffset()) + { + return getDownlinkFrequency(channelNumber) + getTransmitOffset(); + } + + return 0; + } + + @Override + public boolean isTDMA() + { + return false; + } + + @Override + public int getTimeslotCount() + { + return 1; + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/FrequencyBandUpdateTDMA.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/FrequencyBandUpdateTDMA.java new file mode 100644 index 000000000..869145127 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/FrequencyBandUpdateTDMA.java @@ -0,0 +1,164 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.ChannelType; + +import java.util.Collections; +import java.util.List; + +/** + * Identifier update (frequency band) - TDMA bands + */ +public class FrequencyBandUpdateTDMA extends MacStructure implements IFrequencyBand +{ + private static final int[] FREQUENCY_BAND_IDENTIFIER = {8, 9, 10, 11}; + private static final int[] CHANNEL_TYPE = {12, 13, 14, 15}; + 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 ChannelType mChannelType; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public FrequencyBandUpdateTDMA(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" ID:").append(getIdentifier()); + sb.append(" OFFSET:").append(getTransmitOffset()); + sb.append(" SPACING:").append(getChannelSpacing()); + sb.append(" BASE:").append(getBaseFrequency()); + sb.append(" ").append(getChannelType()); + return sb.toString(); + } + + public ChannelType getChannelType() + { + if(mChannelType == null) + { + mChannelType = ChannelType.fromValue(getMessage().getInt(CHANNEL_TYPE, getOffset())); + } + + return mChannelType; + } + + @Override + public int getIdentifier() + { + return getMessage().getInt(FREQUENCY_BAND_IDENTIFIER, getOffset()); + } + + @Override + public long getChannelSpacing() + { + return getMessage().getInt(CHANNEL_SPACING, getOffset()) * 125; + } + + @Override + public long getBaseFrequency() + { + return getMessage().getLong(BASE_FREQUENCY, getOffset()) * 5; + } + + @Override + public int getBandwidth() + { + return getChannelType().getBandwidth(); + } + + @Override + public long getTransmitOffset() + { + long offset = getMessage().getLong(TRANSMIT_OFFSET, getOffset()) * getChannelType().getBandwidth(); + + if(!getMessage().get(TRANSMIT_OFFSET_SIGN + getOffset())) + { + offset *= -1; + } + + return offset; + } + + /** + * Indicates if the frequency band has a transmit option for the subscriber unit. + */ + public boolean hasTransmitOffset() + { + return getMessage().getInt(TRANSMIT_OFFSET, getOffset()) != 0x80; + } + + @Override + public long getDownlinkFrequency(int channelNumber) + { + return getBaseFrequency() + (getChannelSpacing() * (int)(Math.floor(channelNumber / getTimeslotCount()))); + } + + @Override + public long getUplinkFrequency(int channelNumber) + { + if(hasTransmitOffset()) + { + return getDownlinkFrequency(channelNumber) + getTransmitOffset(); + } + + return 0; + } + + @Override + public boolean isTDMA() + { + return getChannelType().isTDMA(); + } + + @Override + public int getTimeslotCount() + { + return getChannelType().getSlotsPerCarrier(); + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/FrequencyBandUpdateVUHF.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/FrequencyBandUpdateVUHF.java new file mode 100644 index 000000000..9228d467a --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/FrequencyBandUpdateVUHF.java @@ -0,0 +1,162 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBand; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.Collections; +import java.util.List; + +/** + * Identifier update (frequency band) - VHF/UHF bands + */ +public class FrequencyBandUpdateVUHF extends MacStructure 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 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}; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public FrequencyBandUpdateVUHF(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" ID:").append(getIdentifier()); + sb.append(" OFFSET:").append(getTransmitOffset()); + sb.append(" SPACING:").append(getChannelSpacing()); + sb.append(" BASE:").append(getBaseFrequency()); + sb.append(" FDMA BW:").append(getBandwidth()); + return sb.toString(); + } + + @Override + public int getIdentifier() + { + return getMessage().getInt(FREQUENCY_BAND_IDENTIFIER, getOffset()); + } + + @Override + public long getChannelSpacing() + { + return getMessage().getInt(CHANNEL_SPACING, getOffset()) * 125; + } + + @Override + public long getBaseFrequency() + { + return getMessage().getLong(BASE_FREQUENCY, getOffset()) * 5; + } + + @Override + public int getBandwidth() + { + int bandwidth = getMessage().getInt(BANDWIDTH, getOffset()); + + if(bandwidth == 0x4) + { + return 6250; + } + else if(bandwidth == 0x5) + { + return 12500; + } + + return 0; + } + + @Override + public long getTransmitOffset() + { + long offset = getMessage().getLong(TRANSMIT_OFFSET, getOffset()) * getChannelSpacing(); + + if(!getMessage().get(TRANSMIT_OFFSET_SIGN + getOffset())) + { + offset *= -1; + } + + return offset; + } + + /** + * Indicates if the frequency band has a transmit option for the subscriber unit. + */ + public boolean hasTransmitOffset() + { + return getMessage().getInt(TRANSMIT_OFFSET, getOffset()) != 0x80; + } + + @Override + public long getDownlinkFrequency(int channelNumber) + { + return getBaseFrequency() + (getChannelSpacing() * channelNumber); + } + + @Override + public long getUplinkFrequency(int channelNumber) + { + if(hasTransmitOffset()) + { + return getDownlinkFrequency(channelNumber) + getTransmitOffset(); + } + + return 0; + } + + @Override + public boolean isTDMA() + { + return false; + } + + @Override + public int getTimeslotCount() + { + return 1; + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupAffiliationQueryAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupAffiliationQueryAbbreviated.java new file mode 100644 index 000000000..db9da41dc --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupAffiliationQueryAbbreviated.java @@ -0,0 +1,110 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Group affiliation query - abbreviated format + */ +public class GroupAffiliationQueryAbbreviated extends MacStructure +{ + private static final int[] TARGET_ADDRESS = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31}; + private static final int[] SOURCE_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private TalkgroupIdentifier mSourceAddress; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public GroupAffiliationQueryAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceAddress()); + return sb.toString(); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupAffiliationQueryExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupAffiliationQueryExtended.java new file mode 100644 index 000000000..0c7f35157 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupAffiliationQueryExtended.java @@ -0,0 +1,114 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FullyQualifiedIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Group affiliation query - extended format + */ +public class GroupAffiliationQueryExtended extends MacStructure +{ + private static final int[] TARGET_ADDRESS = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31}; + private static final int[] SOURCE_WACN = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51}; + private static final int[] SOURCE_SYSTEM = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; + private static final int[] SOURCE_ADDRESS = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private APCO25FullyQualifiedIdentifier mSourceSuid; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public GroupAffiliationQueryExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceSuid()); + return sb.toString(); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public APCO25FullyQualifiedIdentifier getSourceSuid() + { + if(mSourceSuid == null) + { + mSourceSuid = APCO25FullyQualifiedIdentifier.createFrom(getMessage().getInt(SOURCE_WACN, getOffset()), + getMessage().getInt(SOURCE_SYSTEM, getOffset()), getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceSuid; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceSuid()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupPagingMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupPagingMessage.java new file mode 100644 index 000000000..c85eed353 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupPagingMessage.java @@ -0,0 +1,211 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Group paging message + */ +public class GroupPagingMessage extends MacStructure +{ + private static final int[] ID_COUNT = {14, 15}; + private static final int[] GROUP_ADDRESS_1 = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] GROUP_ADDRESS_2 = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + private static final int[] GROUP_ADDRESS_3 = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; + private static final int[] GROUP_ADDRESS_4 = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress1; + private TalkgroupIdentifier mTargetAddress2; + private TalkgroupIdentifier mTargetAddress3; + private TalkgroupIdentifier mTargetAddress4; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public GroupPagingMessage(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" GROUP1:").append(getTargetAddress1()); + + int count = getCount(); + + if(count > 1) + { + sb.append(" GROUP2:").append(getTargetAddress2()); + + if(count > 2) + { + sb.append(" GROUP3:").append(getTargetAddress3()); + + if(count > 3) + { + sb.append(" GROUP4:").append(getTargetAddress4()); + } + } + } + + return sb.toString(); + } + + public static int getIdCount(BinaryMessage message, int offset) + { + return message.getInt(ID_COUNT, offset); + } + + /** + * Number of paging target addresses contained in this message + * @return addresses count (1 - 4) + */ + public int getCount() + { + return getIdCount(getMessage(), getOffset()); + } + + /** + * Length of the individual paging message in bytes + * + * @return + */ + public static int getLength(BinaryMessage message, int offset) + { + int count = getIdCount(message, offset); + + switch(count) + { + case 1: + return 4; + case 2: + return 6; + case 3: + return 8; + case 4: + return 10; + } + + return 4; + } + + /** + * To Talkgroup 1 + */ + public TalkgroupIdentifier getTargetAddress1() + { + if(mTargetAddress1 == null) + { + mTargetAddress1 = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS_1, getOffset())); + } + + return mTargetAddress1; + } + + /** + * To Talkgroup 2 + */ + public TalkgroupIdentifier getTargetAddress2() + { + if(mTargetAddress2 == null && getCount() >= 2) + { + mTargetAddress2 = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS_2, getOffset())); + } + + return mTargetAddress2; + } + + /** + * To Talkgroup 3 + */ + public TalkgroupIdentifier getTargetAddress3() + { + if(mTargetAddress3 == null && getCount() >= 3) + { + mTargetAddress3 = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS_3, getOffset())); + } + + return mTargetAddress3; + } + + /** + * To Talkgroup 4 + */ + public TalkgroupIdentifier getTargetAddress4() + { + if(mTargetAddress4 == null && getCount() >= 4) + { + mTargetAddress4 = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS_4, getOffset())); + } + + return mTargetAddress4; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + + int count = getCount(); + + mIdentifiers.add(getTargetAddress1()); + + if(count > 1) + { + mIdentifiers.add(getTargetAddress2()); + + if(count > 2) + { + mIdentifiers.add(getTargetAddress3()); + + if(count > 3) + { + mIdentifiers.add(getTargetAddress4()); + } + } + } + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantAbbreviated.java new file mode 100644 index 000000000..540c0335b --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantAbbreviated.java @@ -0,0 +1,157 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; +import io.github.dsheirer.module.decode.p25.identifier.channel.P25P2Channel; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Group voice channel grant - abbreviated format + */ +public class GroupVoiceChannelGrantAbbreviated extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] FREQUENCY_BAND = {16, 17, 18, 19}; + private static final int[] CHANNEL_NUMBER = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + 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 List mIdentifiers; + private APCO25Channel mChannel; + private TalkgroupIdentifier mGroupAddress; + private TalkgroupIdentifier mSourceAddress; + private VoiceServiceOptions mServiceOptions; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public GroupVoiceChannelGrantAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getGroupAddress()); + sb.append(" FM:").append(getSourceAddress()); + sb.append(" CHAN:").append(getChannel()); + sb.append(" ").append(getServiceOptions()); + return sb.toString(); + } + + /** + * Voice channel service options + */ + public VoiceServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * Channel + */ + public APCO25Channel getChannel() + { + if(mChannel == null) + { + mChannel = new APCO25Channel(new P25P2Channel(getMessage().getInt(FREQUENCY_BAND, getOffset()), + getMessage().getInt(CHANNEL_NUMBER, getOffset()))); + } + + return mChannel; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getGroupAddress() + { + if(mGroupAddress == null) + { + mGroupAddress = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS, getOffset())); + } + + return mGroupAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getGroupAddress()); + mIdentifiers.add(getSourceAddress()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannel()); + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantExtended.java new file mode 100644 index 000000000..3de039f42 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantExtended.java @@ -0,0 +1,161 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +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.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Group voice channel grant - extended format + */ +public class GroupVoiceChannelGrantExtended extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] TRANSMIT_FREQUENCY_BAND = {16, 17, 18, 19}; + private static final int[] TRANSMIT_CHANNEL_NUMBER = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] RECEIVE_FREQUENCY_BAND = {32, 33, 34, 35}; + private static final int[] RECEIVE_CHANNEL_NUMBER = {36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + private static final int[] GROUP_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; + private static final int[] SOURCE_ADDRESS = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87}; + + private List mIdentifiers; + private APCO25Channel mChannel; + private TalkgroupIdentifier mGroupAddress; + private TalkgroupIdentifier mSourceAddress; + private VoiceServiceOptions mServiceOptions; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public GroupVoiceChannelGrantExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getGroupAddress()); + sb.append(" FM:").append(getSourceAddress()); + sb.append(" CHAN:").append(getChannel()); + sb.append(" ").append(getServiceOptions()); + return sb.toString(); + } + + /** + * Voice channel service options + */ + public VoiceServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * Channel + */ + public APCO25Channel getChannel() + { + if(mChannel == null) + { + mChannel = APCO25ExplicitChannel.create(getMessage().getInt(TRANSMIT_FREQUENCY_BAND, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER, getOffset()), + getMessage().getInt(RECEIVE_FREQUENCY_BAND, getOffset()), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER, getOffset())); + } + + return mChannel; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getGroupAddress() + { + if(mGroupAddress == null) + { + mGroupAddress = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS, getOffset())); + } + + return mGroupAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getGroupAddress()); + mIdentifiers.add(getSourceAddress()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannel()); + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantUpdate.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantUpdate.java new file mode 100644 index 000000000..2d053b336 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantUpdate.java @@ -0,0 +1,153 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; +import io.github.dsheirer.module.decode.p25.identifier.channel.P25P2Channel; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Group voice channel grant update + */ +public class GroupVoiceChannelGrantUpdate extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] FREQUENCY_BAND_A = {8, 9, 10, 11}; + private static final int[] CHANNEL_NUMBER_A = {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] GROUP_ADDRESS_A = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; + private static final int[] FREQUENCY_BAND_B = {40, 41, 42, 43}; + private static final int[] CHANNEL_NUMBER_B = {44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55}; + private static final int[] GROUP_ADDRESS_B = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71}; + + private List mIdentifiers; + private TalkgroupIdentifier mGroupAddressA; + private APCO25Channel mChannelA; + private TalkgroupIdentifier mGroupAddressB; + private APCO25Channel mChannelB; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public GroupVoiceChannelGrantUpdate(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" GROUP A:").append(getGroupAddressA()); + sb.append(" CHAN-A:").append(getChannelA()); + sb.append(" GROUP B:").append(getGroupAddressB()); + sb.append(" CHAN-B:").append(getChannelB()); + return sb.toString(); + } + + public APCO25Channel getChannelA() + { + if(mChannelA == null) + { + mChannelA = new APCO25Channel(new P25P2Channel(getMessage().getInt(FREQUENCY_BAND_A, getOffset()), + getMessage().getInt(CHANNEL_NUMBER_A, getOffset()))); + } + + return mChannelA; + } + + public APCO25Channel getChannelB() + { + if(mChannelB == null) + { + mChannelB = new APCO25Channel(new P25P2Channel(getMessage().getInt(FREQUENCY_BAND_B, getOffset()), + getMessage().getInt(CHANNEL_NUMBER_B, getOffset()))); + } + + return mChannelB; + } + + + /** + * Talkgroup channel A + */ + public TalkgroupIdentifier getGroupAddressA() + { + if(mGroupAddressA == null) + { + mGroupAddressA = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS_A, getOffset())); + } + + return mGroupAddressA; + } + + /** + * Talkgroup channel B + */ + public TalkgroupIdentifier getGroupAddressB() + { + if(mGroupAddressB == null) + { + mGroupAddressB = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS_B, getOffset())); + } + + return mGroupAddressB; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getChannelA()); + mIdentifiers.add(getChannelB()); + mIdentifiers.add(getGroupAddressA()); + mIdentifiers.add(getGroupAddressB()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannelA()); + channels.add(getChannelB()); + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantUpdateExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantUpdateExplicit.java new file mode 100644 index 000000000..d486c86c4 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantUpdateExplicit.java @@ -0,0 +1,136 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +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.channel.P25P2ExplicitChannel; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Group voice channel grant update - explicit channel format + */ +public class GroupVoiceChannelGrantUpdateExplicit extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] TRANSMIT_FREQUENCY_BAND = {16, 17, 18, 19}; + private static final int[] TRANSMIT_CHANNEL_NUMBER = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] RECEIVE_FREQUENCY_BAND = {32, 33, 34, 35}; + private static final int[] RECEIVE_CHANNEL_NUMBER = {36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + private static final int[] GROUP_ADDRESS = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; + + private List mIdentifiers; + private VoiceServiceOptions mVoiceServiceOptions; + private TalkgroupIdentifier mGroupAddress; + private APCO25Channel mChannel; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public GroupVoiceChannelGrantUpdateExplicit(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" GROUP:").append(getGroupAddress()); + sb.append(" CHAN:").append(getChannel()); + return sb.toString(); + } + + public VoiceServiceOptions getVoiceServiceOptions() + { + if(mVoiceServiceOptions == null) + { + mVoiceServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mVoiceServiceOptions; + } + + public APCO25Channel getChannel() + { + if(mChannel == null) + { + mChannel = new APCO25ExplicitChannel(new P25P2ExplicitChannel(getMessage().getInt(TRANSMIT_FREQUENCY_BAND, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER, getOffset()), + getMessage().getInt(RECEIVE_FREQUENCY_BAND, getOffset()), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER, getOffset()))); + } + + return mChannel; + } + + /** + * Talkgroup channel A + */ + public TalkgroupIdentifier getGroupAddress() + { + if(mGroupAddress == null) + { + mGroupAddress = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS, getOffset())); + } + + return mGroupAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getChannel()); + mIdentifiers.add(getGroupAddress()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannel()); + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantUpdateMultiple.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantUpdateMultiple.java new file mode 100644 index 000000000..0eda81cc0 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantUpdateMultiple.java @@ -0,0 +1,257 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; +import io.github.dsheirer.module.decode.p25.identifier.channel.P25P2Channel; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Group voice channel grant update - multiple users/channels + */ +public class GroupVoiceChannelGrantUpdateMultiple extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] SERVICE_OPTIONS_A = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] FREQUENCY_BAND_A = {16, 17, 18, 19}; + private static final int[] CHANNEL_NUMBER_A = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] GROUP_ADDRESS_A = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + + private static final int[] SERVICE_OPTIONS_B = {48, 49, 50, 51, 52, 53, 54, 55}; + private static final int[] FREQUENCY_BAND_B = {56, 57, 58, 59}; + private static final int[] CHANNEL_NUMBER_B = {60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71}; + private static final int[] GROUP_ADDRESS_B = {72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87}; + + private static final int[] SERVICE_OPTIONS_C = {88, 89, 90, 91, 92, 93, 94, 95}; + private static final int[] FREQUENCY_BAND_C = {96, 97, 98, 99}; + private static final int[] CHANNEL_NUMBER_C = {100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111}; + private static final int[] GROUP_ADDRESS_C = {112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127}; + + private List mIdentifiers; + private VoiceServiceOptions mVoiceServiceOptionsA; + private TalkgroupIdentifier mGroupAddressA; + private APCO25Channel mChannelA; + private VoiceServiceOptions mVoiceServiceOptionsB; + private TalkgroupIdentifier mGroupAddressB; + private APCO25Channel mChannelB; + private VoiceServiceOptions mVoiceServiceOptionsC; + private TalkgroupIdentifier mGroupAddressC; + private APCO25Channel mChannelC; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public GroupVoiceChannelGrantUpdateMultiple(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" GROUP-A:").append(getGroupAddressA()); + sb.append(" CHAN-A:").append(getChannelA()); + sb.append(" ").append(getVoiceServiceOptionsA()); + + if(hasGroupB()) + { + sb.append(" GROUP-B:").append(getGroupAddressB()); + sb.append(" CHAN-B:").append(getChannelB()); + sb.append(" ").append(getVoiceServiceOptionsB()); + } + + if(hasGroupC()) + { + sb.append(" GROUP-C:").append(getGroupAddressC()); + sb.append(" CHAN-C:").append(getChannelC()); + sb.append(" ").append(getVoiceServiceOptionsC()); + } + + return sb.toString(); + } + + /** + * Indicates if this message contains a group address B and corresponding channel. + */ + public boolean hasGroupB() + { + int groupB = getMessage().getInt(GROUP_ADDRESS_B, getOffset()); + return getMessage().getInt(GROUP_ADDRESS_A, getOffset()) != groupB && groupB != 0; + } + + /** + * Indicates if this message contains a group address C and corresponding channel. + */ + public boolean hasGroupC() + { + int groupC = getMessage().getInt(GROUP_ADDRESS_C, getOffset()); + return getMessage().getInt(GROUP_ADDRESS_A, getOffset()) != groupC && + getMessage().getInt(GROUP_ADDRESS_B, getOffset()) != groupC && groupC != 0; + } + + public VoiceServiceOptions getVoiceServiceOptionsA() + { + if(mVoiceServiceOptionsA == null) + { + mVoiceServiceOptionsA = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS_A, getOffset())); + } + + return mVoiceServiceOptionsA; + } + + public VoiceServiceOptions getVoiceServiceOptionsB() + { + if(mVoiceServiceOptionsB == null) + { + mVoiceServiceOptionsB = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS_B, getOffset())); + } + + return mVoiceServiceOptionsB; + } + + public VoiceServiceOptions getVoiceServiceOptionsC() + { + if(mVoiceServiceOptionsC == null) + { + mVoiceServiceOptionsC = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS_C, getOffset())); + } + + return mVoiceServiceOptionsC; + } + + public APCO25Channel getChannelA() + { + if(mChannelA == null) + { + mChannelA = new APCO25Channel(new P25P2Channel(getMessage().getInt(FREQUENCY_BAND_A, getOffset()), + getMessage().getInt(CHANNEL_NUMBER_A, getOffset()))); + } + + return mChannelA; + } + + public APCO25Channel getChannelB() + { + if(mChannelB == null) + { + mChannelB = new APCO25Channel(new P25P2Channel(getMessage().getInt(FREQUENCY_BAND_B, getOffset()), + getMessage().getInt(CHANNEL_NUMBER_B, getOffset()))); + } + + return mChannelB; + } + + public APCO25Channel getChannelC() + { + if(mChannelC == null) + { + mChannelC = new APCO25Channel(new P25P2Channel(getMessage().getInt(FREQUENCY_BAND_C, getOffset()), + getMessage().getInt(CHANNEL_NUMBER_C, getOffset()))); + } + + return mChannelC; + } + + /** + * Talkgroup channel A + */ + public TalkgroupIdentifier getGroupAddressA() + { + if(mGroupAddressA == null) + { + mGroupAddressA = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS_A, getOffset())); + } + + return mGroupAddressA; + } + + /** + * Talkgroup channel B + */ + public TalkgroupIdentifier getGroupAddressB() + { + if(mGroupAddressB == null) + { + mGroupAddressB = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS_B, getOffset())); + } + + return mGroupAddressB; + } + + /** + * Talkgroup channel C + */ + public TalkgroupIdentifier getGroupAddressC() + { + if(mGroupAddressC == null) + { + mGroupAddressC = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS_C, getOffset())); + } + + return mGroupAddressC; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getChannelA()); + mIdentifiers.add(getChannelB()); + mIdentifiers.add(getChannelC()); + mIdentifiers.add(getGroupAddressA()); + mIdentifiers.add(getGroupAddressB()); + mIdentifiers.add(getGroupAddressC()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannelA()); + channels.add(getChannelB()); + channels.add(getChannelC()); + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantUpdateMultipleExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantUpdateMultipleExplicit.java new file mode 100644 index 000000000..b6ee4f827 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelGrantUpdateMultipleExplicit.java @@ -0,0 +1,205 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +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.channel.P25P2ExplicitChannel; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Group voice channel grant update multiple - explicit + */ +public class GroupVoiceChannelGrantUpdateMultipleExplicit extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] SERVICE_OPTIONS_A = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] TRANSMIT_FREQUENCY_BAND_A = {16, 17, 18, 19}; + private static final int[] TRANSMIT_CHANNEL_NUMBER_A = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] RECEIVE_FREQUENCY_BAND_A = {32, 33, 34, 35}; + private static final int[] RECEIVE_CHANNEL_NUMBER_A = {36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + private static final int[] GROUP_ADDRESS_A = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; + + private static final int[] SERVICE_OPTIONS_B = {64, 65, 66, 67, 68, 69, 70, 71}; + private static final int[] TRANSMIT_FREQUENCY_BAND_B = {72, 73, 74, 75}; + private static final int[] TRANSMIT_CHANNEL_NUMBER_B = {76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87}; + private static final int[] RECEIVE_FREQUENCY_BAND_B = {88, 89, 90, 91}; + private static final int[] RECEIVE_CHANNEL_NUMBER_B = {92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103}; + private static final int[] GROUP_ADDRESS_B = {104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119}; + + private List mIdentifiers; + private VoiceServiceOptions mVoiceServiceOptionsA; + private TalkgroupIdentifier mGroupAddressA; + private APCO25Channel mChannelA; + private VoiceServiceOptions mVoiceServiceOptionsB; + private TalkgroupIdentifier mGroupAddressB; + private APCO25Channel mChannelB; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public GroupVoiceChannelGrantUpdateMultipleExplicit(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" GROUP-A:").append(getGroupAddressA()); + sb.append(" CHAN-A:").append(getChannelA()); + sb.append(" ").append(getVoiceServiceOptionsA()); + + if(hasGroupB()) + { + sb.append(" GROUP-B:").append(getGroupAddressB()); + sb.append(" CHAN-B:").append(getChannelB()); + sb.append(" ").append(getVoiceServiceOptionsB()); + } + + return sb.toString(); + } + + /** + * Indicates if this message contains a group address B and corresponding channel. + */ + public boolean hasGroupB() + { + int groupB = getMessage().getInt(GROUP_ADDRESS_B, getOffset()); + return getMessage().getInt(GROUP_ADDRESS_A, getOffset()) != groupB && groupB != 0; + } + + + public VoiceServiceOptions getVoiceServiceOptionsA() + { + if(mVoiceServiceOptionsA == null) + { + mVoiceServiceOptionsA = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS_A, getOffset())); + } + + return mVoiceServiceOptionsA; + } + + public VoiceServiceOptions getVoiceServiceOptionsB() + { + if(mVoiceServiceOptionsB == null) + { + mVoiceServiceOptionsB = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS_B, getOffset())); + } + + return mVoiceServiceOptionsB; + } + + public APCO25Channel getChannelA() + { + if(mChannelA == null) + { + mChannelA = new APCO25ExplicitChannel(new P25P2ExplicitChannel(getMessage().getInt(TRANSMIT_FREQUENCY_BAND_A, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER_A, getOffset()), + getMessage().getInt(RECEIVE_FREQUENCY_BAND_A, getOffset()), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER_A, getOffset()))); + } + + return mChannelA; + } + + public APCO25Channel getChannelB() + { + if(mChannelB == null) + { + mChannelB = new APCO25ExplicitChannel(new P25P2ExplicitChannel(getMessage().getInt(TRANSMIT_FREQUENCY_BAND_B, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER_B, getOffset()), + getMessage().getInt(RECEIVE_FREQUENCY_BAND_B, getOffset()), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER_B, getOffset()))); + } + + return mChannelB; + } + + /** + * Talkgroup channel A + */ + public TalkgroupIdentifier getGroupAddressA() + { + if(mGroupAddressA == null) + { + mGroupAddressA = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS_A, getOffset())); + } + + return mGroupAddressA; + } + + /** + * Talkgroup channel B + */ + public TalkgroupIdentifier getGroupAddressB() + { + if(mGroupAddressB == null) + { + mGroupAddressB = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS_B, getOffset())); + } + + return mGroupAddressB; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getChannelA()); + mIdentifiers.add(getChannelB()); + mIdentifiers.add(getGroupAddressA()); + mIdentifiers.add(getGroupAddressB()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannelA()); + channels.add(getChannelB()); + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelUserAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelUserAbbreviated.java new file mode 100644 index 000000000..d7f225334 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelUserAbbreviated.java @@ -0,0 +1,126 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Group voice channel user - abbreviated format + */ +public class GroupVoiceChannelUserAbbreviated extends MacStructure +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] GROUP_ADDRESS = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] SOURCE_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + + private List mIdentifiers; + private TalkgroupIdentifier mGroupAddress; + private TalkgroupIdentifier mSourceAddress; + private VoiceServiceOptions mServiceOptions; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public GroupVoiceChannelUserAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getGroupAddress()); + sb.append(" FM:").append(getSourceAddress()); + sb.append(" ").append(getServiceOptions()); + return sb.toString(); + } + + /** + * Voice channel service options + */ + public VoiceServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getGroupAddress() + { + if(mGroupAddress == null) + { + mGroupAddress = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS, getOffset())); + } + + return mGroupAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getGroupAddress()); + mIdentifiers.add(getSourceAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelUserExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelUserExtended.java new file mode 100644 index 000000000..1a8062582 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceChannelUserExtended.java @@ -0,0 +1,150 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FullyQualifiedIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Group voice channel user - abbreviated format + */ +public class GroupVoiceChannelUserExtended extends MacStructure +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] GROUP_ADDRESS = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] SOURCE_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + private static final int[] FULLY_QUALIFIED_SOURCE_WACN = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75}; + private static final int[] FULLY_QUALIFIED_SOURCE_SYSTEM = {76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87}; + private static final int[] FULLY_QUALIFIED_SOURCE_ID = {88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111}; + + + private List mIdentifiers; + private VoiceServiceOptions mServiceOptions; + private TalkgroupIdentifier mGroupAddress; + private TalkgroupIdentifier mSourceAddress; + private APCO25FullyQualifiedIdentifier mSourceSuid; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public GroupVoiceChannelUserExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getGroupAddress()); + sb.append(" FM:").append(getSourceAddress()); + sb.append(" SUID:").append(getSourceSuid()); + sb.append(" ").append(getServiceOptions()); + return sb.toString(); + } + + /** + * Voice channel service options + */ + public VoiceServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getGroupAddress() + { + if(mGroupAddress == null) + { + mGroupAddress = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS, getOffset())); + } + + return mGroupAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + public APCO25FullyQualifiedIdentifier getSourceSuid() + { + if(mSourceSuid == null) + { + int wacn = getMessage().getInt(FULLY_QUALIFIED_SOURCE_WACN, getOffset()); + int system = getMessage().getInt(FULLY_QUALIFIED_SOURCE_SYSTEM, getOffset()); + int id = getMessage().getInt(FULLY_QUALIFIED_SOURCE_ID, getOffset()); + + mSourceSuid = APCO25FullyQualifiedIdentifier.createFrom(wacn, system, id); + } + + return mSourceSuid; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getGroupAddress()); + mIdentifiers.add(getSourceAddress()); + mIdentifiers.add(getSourceSuid()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceServiceRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceServiceRequest.java new file mode 100644 index 000000000..797a55e66 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/GroupVoiceServiceRequest.java @@ -0,0 +1,126 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Group voice service request - abbreviated format + */ +public class GroupVoiceServiceRequest extends MacStructure +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] GROUP_ADDRESS = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] SOURCE_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + + private List mIdentifiers; + private TalkgroupIdentifier mGroupAddress; + private TalkgroupIdentifier mSourceAddress; + private VoiceServiceOptions mServiceOptions; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public GroupVoiceServiceRequest(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getGroupAddress()); + sb.append(" FM:").append(getSourceAddress()); + sb.append(" ").append(getServiceOptions()); + return sb.toString(); + } + + /** + * Voice channel service options + */ + public VoiceServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getGroupAddress() + { + if(mGroupAddress == null) + { + mGroupAddress = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS, getOffset())); + } + + return mGroupAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getGroupAddress()); + mIdentifiers.add(getSourceAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/IndividualPagingMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/IndividualPagingMessage.java new file mode 100644 index 000000000..7cc2f4f4d --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/IndividualPagingMessage.java @@ -0,0 +1,275 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Individual paging message with priority + */ +public class IndividualPagingMessage extends MacStructure +{ + private static final int PRIORITY_ID_1 = 8; + private static final int PRIORITY_ID_2 = 9; + private static final int PRIORITY_ID_3 = 10; + private static final int PRIORITY_ID_4 = 11; + private static final int[] ID_COUNT = {14, 15}; + private static final int[] TARGET_ADDRESS_1 = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39}; + private static final int[] TARGET_ADDRESS_2 = {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[] TARGET_ADDRESS_3 = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87}; + private static final int[] TARGET_ADDRESS_4 = {88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress1; + private TalkgroupIdentifier mTargetAddress2; + private TalkgroupIdentifier mTargetAddress3; + private TalkgroupIdentifier mTargetAddress4; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public IndividualPagingMessage(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" ID1:").append(getTargetAddress1()); + + if(isTalkgroupPriority1()) + { + sb.append("-HIGH PRIORITY"); + } + else + { + sb.append("-LOW PRIORITY"); + } + + int count = getCount(); + + if(count > 1) + { + sb.append(" ID2:").append(getTargetAddress2()); + + if(isTalkgroupPriority2()) + { + sb.append("-HIGH PRIORITY"); + } + else + { + sb.append("-LOW PRIORITY"); + } + + if(count > 2) + { + sb.append(" ID3:").append(getTargetAddress3()); + + if(isTalkgroupPriority3()) + { + sb.append("-HIGH PRIORITY"); + } + else + { + sb.append("-LOW PRIORITY"); + } + + if(count > 3) + { + sb.append(" ID4:").append(getTargetAddress4()); + + if(isTalkgroupPriority4()) + { + sb.append("-HIGH PRIORITY"); + } + else + { + sb.append("-LOW PRIORITY"); + } + } + } + } + + return sb.toString(); + } + + public static int getIdCount(BinaryMessage message, int offset) + { + return message.getInt(ID_COUNT, offset); + } + + /** + * Number of paging target addresses contained in this message + * @return addresses count (1 - 4) + */ + public int getCount() + { + return getIdCount(getMessage(), getOffset()); + } + + /** + * Length of the individual paging message in bytes + * + * @return + */ + public static int getLength(BinaryMessage message, int offset) + { + int count = getIdCount(message, offset); + + switch(count) + { + case 1: + return 5; + case 2: + return 8; + case 3: + return 11; + case 4: + return 14; + } + + return 5; + } + + public boolean isTalkgroupPriority1() + { + return getMessage().get(PRIORITY_ID_1 + getOffset()); + } + + public boolean isTalkgroupPriority2() + { + return getMessage().get(PRIORITY_ID_2 + getOffset()); + } + + public boolean isTalkgroupPriority3() + { + return getMessage().get(PRIORITY_ID_3 + getOffset()); + } + + public boolean isTalkgroupPriority4() + { + return getMessage().get(PRIORITY_ID_4 + getOffset()); + } + + /** + * To Talkgroup 1 + */ + public TalkgroupIdentifier getTargetAddress1() + { + if(mTargetAddress1 == null) + { + mTargetAddress1 = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS_1, getOffset())); + } + + return mTargetAddress1; + } + + /** + * To Talkgroup 2 + */ + public TalkgroupIdentifier getTargetAddress2() + { + if(mTargetAddress2 == null && getCount() >= 2) + { + mTargetAddress2 = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS_2, getOffset())); + } + + return mTargetAddress2; + } + + /** + * To Talkgroup 3 + */ + public TalkgroupIdentifier getTargetAddress3() + { + if(mTargetAddress3 == null && getCount() >= 3) + { + mTargetAddress3 = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS_3, getOffset())); + } + + return mTargetAddress3; + } + + /** + * To Talkgroup 4 + */ + public TalkgroupIdentifier getTargetAddress4() + { + if(mTargetAddress4 == null && getCount() >= 4) + { + mTargetAddress4 = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS_4, getOffset())); + } + + return mTargetAddress4; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + + int count = getCount(); + + mIdentifiers.add(getTargetAddress1()); + + if(count > 1) + { + mIdentifiers.add(getTargetAddress2()); + + if(count > 2) + { + mIdentifiers.add(getTargetAddress3()); + + if(count > 3) + { + mIdentifiers.add(getTargetAddress4()); + } + } + } + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/MacRelease.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/MacRelease.java new file mode 100644 index 000000000..367f46e31 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/MacRelease.java @@ -0,0 +1,145 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Nac; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * MAC release / call or talker preemption + */ +public class MacRelease extends MacStructure +{ + private static final int UNFORCED_FORCED_FLAG = 8; + private static final int CALL_AUDIO_FLAG = 9; + private static final int[] TARGET_ADDRESS = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39}; + private static final int[] COLOR_CODE = {44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private Identifier mNac; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public MacRelease(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" NAC:").append(getNac()); + if(isForcedPreemption()) + { + sb.append(" FORCED"); + } + else + { + sb.append(" UNFORCED"); + } + + if(isTalkerPreemption()) + { + sb.append(" TALKER"); + } + else + { + sb.append(" CALL"); + } + + sb.append(" PREEMPTION"); + + return sb.toString(); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + public Identifier getNac() + { + if(mNac == null) + { + mNac = APCO25Nac.create(getMessage().getInt(COLOR_CODE, getOffset())); + } + + return mNac; + } + + /** + * Indicates if this is a forced (true) or unforced (false) preemption. + */ + public boolean isForcedPreemption() + { + return getMessage().get(UNFORCED_FORCED_FLAG + getOffset()); + } + + /** + * Indicates if the call is a talker preemption (true) or call preemption (false) where a talker preemption means + * the current talker is preempted, but the current talkgroup and call will continue. + */ + public boolean isTalkerPreemption() + { + return getMessage().get(CALL_AUDIO_FLAG + getOffset()); + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getNac()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/MessageUpdateAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/MessageUpdateAbbreviated.java new file mode 100644 index 000000000..01c435140 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/MessageUpdateAbbreviated.java @@ -0,0 +1,129 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.message.APCO25ShortDataMessage; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Message update - abbreviated format + */ +public class MessageUpdateAbbreviated extends MacStructure +{ + private static final int[] MESSAGE = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] TARGET_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + private static final int[] SOURCE_ADDRESS = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79}; + + private List mIdentifiers; + private Identifier mShortDataMessage; + private TalkgroupIdentifier mTargetAddress; + private TalkgroupIdentifier mSourceAddress; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public MessageUpdateAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceAddress()); + sb.append(" MSG:").append(getShortDataMessage()); + return sb.toString(); + } + + /** + * Short data message + */ + public Identifier getShortDataMessage() + { + if(mShortDataMessage == null) + { + mShortDataMessage = APCO25ShortDataMessage.create(getMessage().getInt(MESSAGE)); + } + + return mShortDataMessage; + } + + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + mIdentifiers.add(getShortDataMessage()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/MessageUpdateExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/MessageUpdateExtended.java new file mode 100644 index 000000000..075beded8 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/MessageUpdateExtended.java @@ -0,0 +1,133 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.message.APCO25ShortDataMessage; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FullyQualifiedIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Message update - abbreviated format + */ +public class MessageUpdateExtended extends MacStructure +{ + private static final int[] MESSAGE = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] TARGET_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + private static final int[] SOURCE_WACN = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75}; + private static final int[] SOURCE_SYSTEM = {76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87}; + private static final int[] SOURCE_ADDRESS = {88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111}; + + private List mIdentifiers; + private Identifier mShortDataMessage; + private TalkgroupIdentifier mTargetAddress; + private APCO25FullyQualifiedIdentifier mSourceSuid; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public MessageUpdateExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceSuid()); + sb.append(" MSG:").append(getShortDataMessage()); + return sb.toString(); + } + + /** + * Short data message + */ + public Identifier getShortDataMessage() + { + if(mShortDataMessage == null) + { + mShortDataMessage = APCO25ShortDataMessage.create(getMessage().getInt(MESSAGE)); + } + + return mShortDataMessage; + } + + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public APCO25FullyQualifiedIdentifier getSourceSuid() + { + if(mSourceSuid == null) + { + mSourceSuid = APCO25FullyQualifiedIdentifier.createFrom(getMessage().getInt(SOURCE_WACN, getOffset()), + getMessage().getInt(SOURCE_SYSTEM, getOffset()), getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceSuid; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceSuid()); + mIdentifiers.add(getShortDataMessage()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/NetworkStatusBroadcastAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/NetworkStatusBroadcastAbbreviated.java new file mode 100644 index 000000000..6952e951f --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/NetworkStatusBroadcastAbbreviated.java @@ -0,0 +1,189 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Nac; +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.channel.APCO25Channel; +import io.github.dsheirer.module.decode.p25.identifier.channel.P25Channel; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Network status broadcast - abbreviated format + */ +public class NetworkStatusBroadcastAbbreviated extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] LRA = {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_ID = {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 int[] COLOR_CODE = {76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87}; + + private List mIdentifiers; + private Identifier mLRA; + private Identifier mWACN; + private Identifier mSystem; + private APCO25Channel mChannel; + private SystemServiceClass mSystemServiceClass; + private Identifier mNAC; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public NetworkStatusBroadcastAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" WACN:").append(getWACN()); + sb.append(" SYSTEM:").append(getSystem()); + sb.append(" NAC:").append(getNAC()); + sb.append(" LRA:").append(getLRA()); + sb.append(" CHANNEL:").append(getChannel()); + sb.append(" SERVICES:").append(getSystemServiceClass().getServices()); + return sb.toString(); + } + + /** + * Scramble sequence parameters: WACN, SYSTEM and NAC + */ + public ScrambleParameters getScrambleParameters() + { + return new ScrambleParameters(getMessage().getInt(WACN,getOffset()), getMessage().getInt(SYSTEM_ID, getOffset()), + getMessage().getInt(COLOR_CODE, getOffset())); + } + + public Identifier getLRA() + { + if(mLRA == null) + { + mLRA = APCO25Lra.create(getMessage().getInt(LRA, getOffset())); + } + + return mLRA; + } + + public Identifier getWACN() + { + if(mWACN == null) + { + mWACN = APCO25Wacn.create(getMessage().getInt(WACN, getOffset())); + } + + return mWACN; + } + + public Identifier getSystem() + { + if(mSystem == null) + { + mSystem = APCO25System.create(getMessage().getInt(SYSTEM_ID, getOffset())); + } + + return mSystem; + } + + /** + * This channel refers to the control channel for this site. + * + * Note: even though this is broadcast on a Phase II channel, the control channels are currently limited to + * phase 1 and therefore, this should be a Phase 1 control channel. + */ + public APCO25Channel getChannel() + { + if(mChannel == null) + { + P25Channel channel = new P25Channel(getMessage().getInt(FREQUENCY_BAND, getOffset()), + getMessage().getInt(CHANNEL_NUMBER, getOffset())); + mChannel = new APCO25Channel(channel); + } + + return mChannel; + } + + public SystemServiceClass getSystemServiceClass() + { + if(mSystemServiceClass == null) + { + mSystemServiceClass = SystemServiceClass.create(getMessage().getInt(SERVICE_CLASS, getOffset())); + } + + return mSystemServiceClass; + } + + public Identifier getNAC() + { + if(mNAC == null) + { + mNAC = APCO25Nac.create(getMessage().getInt(COLOR_CODE, getOffset())); + } + + return mNAC; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getLRA()); + mIdentifiers.add(getWACN()); + mIdentifiers.add(getSystem()); + mIdentifiers.add(getNAC()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + return Collections.singletonList(getChannel()); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/NetworkStatusBroadcastExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/NetworkStatusBroadcastExtended.java new file mode 100644 index 000000000..fc7106673 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/NetworkStatusBroadcastExtended.java @@ -0,0 +1,186 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Nac; +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.channel.APCO25Channel; +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.phase2.enumeration.ScrambleParameters; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Network status broadcast - extended format + */ +public class NetworkStatusBroadcastExtended extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] LRA = {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_ID = {36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + private static final int[] TRANSMIT_FREQUENCY_BAND = {48, 49, 50, 51}; + private static final int[] TRANSMIT_CHANNEL_NUMBER = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; + private static final int[] RECEIVE_FREQUENCY_BAND = {64, 65, 66, 67}; + private static final int[] RECEIVE_CHANNEL_NUMBER = {68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}; + private static final int[] SERVICE_CLASS = {80, 81, 82, 83, 84, 85, 86, 87}; + private static final int[] COLOR_CODE = {92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103}; + + private List mIdentifiers; + private Identifier mLRA; + private Identifier mWACN; + private Identifier mSystem; + private APCO25Channel mChannel; + private SystemServiceClass mSystemServiceClass; + private Identifier mNAC; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public NetworkStatusBroadcastExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" WACN:").append(getWACN()); + sb.append(" SYSTEM:").append(getSystem()); + sb.append(" NAC:").append(getNAC()); + sb.append(" LRA:").append(getLRA()); + sb.append(" CHANNEL:").append(getChannel()); + sb.append(" SERVICES:").append(getSystemServiceClass().getServices()); + return sb.toString(); + } + + /** + * Scramble sequence parameters: WACN, SYSTEM and NAC + */ + public ScrambleParameters getScrambleParameters() + { + return new ScrambleParameters(getMessage().getInt(WACN, getOffset()), getMessage().getInt(SYSTEM_ID, getOffset()), + getMessage().getInt(COLOR_CODE, getOffset())); + } + + public Identifier getLRA() + { + if(mLRA == null) + { + mLRA = APCO25Lra.create(getMessage().getInt(LRA, getOffset())); + } + + return mLRA; + } + + public Identifier getWACN() + { + if(mWACN == null) + { + mWACN = APCO25Wacn.create(getMessage().getInt(WACN, getOffset())); + } + + return mWACN; + } + + public Identifier getSystem() + { + if(mSystem == null) + { + mSystem = APCO25System.create(getMessage().getInt(SYSTEM_ID, getOffset())); + } + + return mSystem; + } + + public APCO25Channel getChannel() + { + if(mChannel == null) + { + mChannel = APCO25ExplicitChannel.create(getMessage().getInt(TRANSMIT_FREQUENCY_BAND, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER, getOffset()), + getMessage().getInt(RECEIVE_FREQUENCY_BAND, getOffset()), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER, getOffset())); + } + + return mChannel; + } + + public SystemServiceClass getSystemServiceClass() + { + if(mSystemServiceClass == null) + { + mSystemServiceClass = SystemServiceClass.create(getMessage().getInt(SERVICE_CLASS, getOffset())); + } + + return mSystemServiceClass; + } + + public Identifier getNAC() + { + if(mNAC == null) + { + mNAC = APCO25Nac.create(getMessage().getInt(COLOR_CODE, getOffset())); + } + + return mNAC; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getLRA()); + mIdentifiers.add(getWACN()); + mIdentifiers.add(getSystem()); + mIdentifiers.add(getNAC()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + return Collections.singletonList(getChannel()); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/NullInformationMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/NullInformationMessage.java new file mode 100644 index 000000000..94d64a03c --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/NullInformationMessage.java @@ -0,0 +1,60 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.Collections; +import java.util.List; + +/** + * Null (empty) information message + */ +public class NullInformationMessage extends MacStructure +{ + /** + * Constructs the message + * + * @param message containing the message bits + * @param timestamp of the final bit of the message + */ + public NullInformationMessage(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + return getOpcode().toString(); + } + + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/PowerControlSignalQuality.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/PowerControlSignalQuality.java new file mode 100644 index 000000000..7ebf09dae --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/PowerControlSignalQuality.java @@ -0,0 +1,107 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.BER; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.RFLevel; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Power control signal quality + */ +public class PowerControlSignalQuality extends MacStructure +{ + private static final int[] TARGET_ADDRESS = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31}; + private static final int[] RF_LEVEL = {32, 33, 34, 35}; + private static final int[] BIT_ERROR_RATE = {36, 37, 38, 39}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public PowerControlSignalQuality(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" RF-LEVEL:").append(getRFLevel()); + sb.append(" BER:").append(getBitErrorRate()); + return sb.toString(); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + public RFLevel getRFLevel() + { + return RFLevel.fromValue(getMessage().getInt(RF_LEVEL, getOffset())); + } + + public BER getBitErrorRate() + { + return BER.fromValue(getMessage().getInt(BIT_ERROR_RATE, getOffset())); + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/PushToTalk.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/PushToTalk.java new file mode 100644 index 000000000..8c6546a54 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/PushToTalk.java @@ -0,0 +1,176 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.audio.codec.mbe.IEncryptionSyncParameters; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.audio.Phase2EncryptionSyncParameters; +import io.github.dsheirer.module.decode.p25.identifier.encryption.APCO25EncryptionKey; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacOpcode; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Call start. + * + * Similar to a P25 Phase 1 Header Data Unit (HDU). + */ +public class PushToTalk extends MacStructure +{ + private static int MESSAGE_INDICATOR_START = 8; + private static int MESSAGE_INDICATOR_END = 79; + private static int[] ALGORITHM_ID = {80, 81, 82, 83, 84, 85, 86, 87}; + private static int[] KEY_ID = {88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103}; + private static int[] SOURCE_ADDRESS = {104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127}; + private static int[] GROUP_ADDRESS = {128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143}; + + private EncryptionKeyIdentifier mEncryptionKey; + private TalkgroupIdentifier mSourceAddress; + private TalkgroupIdentifier mGroupAddress; + private List mIdentifiers; + + /** + * Constructs the message + * + * @param message containing the message bits + */ + public PushToTalk(CorrectedBinaryMessage message) + { + super(message, 0); + } + + @Override + public MacOpcode getOpcode() + { + return MacOpcode.PUSH_TO_TALK; + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append("FROM:").append(getSourceAddress()); + sb.append(" TO:").append(getGroupAddress()); + + if(isEncrypted()) + { + sb.append(" ").append(getEncryptionKey()); + sb.append(" MI:").append(getMessageIndicator()); + } + + return sb.toString(); + } + + /** + * Indicates if this message is encrypted and an encryption algorithm is specified. + */ + public boolean isEncrypted() + { + return getEncryptionKey().getValue().isEncrypted(); + } + + /** + * Encryption sync parameters + */ + public IEncryptionSyncParameters getEncryptionSyncParameters() + { + return new Phase2EncryptionSyncParameters(getEncryptionKey(), getMessageIndicator()); + } + + /** + * Message indicator value (encryption key generator fill sequence) + */ + public String getMessageIndicator() + { + return getMessage().getHex(MESSAGE_INDICATOR_START + getOffset(), MESSAGE_INDICATOR_END + getOffset()); + } + + + /** + * Encryption key that specifies the encryption algorithm and the key ID + * @return encryption key + */ + public EncryptionKeyIdentifier getEncryptionKey() + { + if(mEncryptionKey == null) + { + mEncryptionKey = EncryptionKeyIdentifier.create(APCO25EncryptionKey.create(getMessage().getInt(ALGORITHM_ID, getOffset()), + getMessage().getInt(KEY_ID, getOffset()))); + } + + return mEncryptionKey; + } + + /** + * Calling (source) radio identifier + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + /** + * Called (destination) group identifier + */ + public TalkgroupIdentifier getGroupAddress() + { + if(mGroupAddress == null) + { + mGroupAddress = APCO25ToTalkgroup.createGroup(getMessage().getInt(GROUP_ADDRESS, getOffset())); + } + + return mGroupAddress; + } + + /** + * List of identifiers contained in this message + */ + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getSourceAddress()); + mIdentifiers.add(getGroupAddress()); + mIdentifiers.add(getEncryptionKey()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/QueuedResponse.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/QueuedResponse.java new file mode 100644 index 000000000..8049c29b8 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/QueuedResponse.java @@ -0,0 +1,138 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacOpcode; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.QueuedResponseReason; + +import java.util.ArrayList; +import java.util.List; + +/** + * Queued response + */ +public class QueuedResponse extends MacStructure +{ + private static final int ADDITIONAL_INFORMATION_INDICATOR = 8; + private static final int[] SERVICE_TYPE = {10, 11, 12, 13, 14, 15}; + private static final int[] REASON = {24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] ADDITIONAL_INFO = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + private static final int[] TARGET_ADDRESS = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79}; + + private QueuedResponseReason mQueuedResponseReason; + private String mAdditionalInfo; + private Identifier mTargetAddress; + private List mIdentifiers; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public QueuedResponse(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" SERVICE:").append(getQueuedResponseServiceType()); + sb.append(" REASON:").append(getQueuedResponseReason()); + + if(hasAdditionalInformation()) + { + sb.append(" INFO:").append(getAdditionalInfo()); + } + + return sb.toString(); + } + + private boolean hasAdditionalInformation() + { + return getMessage().get(ADDITIONAL_INFORMATION_INDICATOR + getOffset()); + } + + public String getAdditionalInfo() + { + if(mAdditionalInfo == null) + { + int arguments = getMessage().getInt(ADDITIONAL_INFO, getOffset()); + mAdditionalInfo = Integer.toHexString(arguments).toUpperCase(); + } + + return mAdditionalInfo; + } + + /** + * Opcode representing the service type that is being acknowledged by the radio unit. + */ + public MacOpcode getQueuedResponseServiceType() + { + return MacOpcode.fromValue(getMessage().getInt(SERVICE_TYPE, getOffset())); + } + + public QueuedResponseReason getQueuedResponseReason() + { + if(mQueuedResponseReason == null) + { + mQueuedResponseReason = QueuedResponseReason.fromCode(getMessage().getInt(REASON, getOffset())); + } + + return mQueuedResponseReason; + } + + public Identifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RadioUnitMonitorCommand.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RadioUnitMonitorCommand.java new file mode 100644 index 000000000..fd20fd532 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RadioUnitMonitorCommand.java @@ -0,0 +1,144 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Radio unit monitor command + */ +public class RadioUnitMonitorCommand extends MacStructure +{ + private static final int[] TRANSMIT_TIME = {16, 17, 18, 19, 20, 21, 22, 23}; + private static final int SILENT_MONITOR = 24; //?? + private static final int[] TRANSMIT_MULTIPLIER = {30, 31}; + private static final int[] TARGET_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55}; + private static final int[] SOURCE_ADDRESS = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79}; + + private List mIdentifiers; + private TalkgroupIdentifier mSourceAddress; + private TalkgroupIdentifier mTargetAddress; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public RadioUnitMonitorCommand(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceAddress()); + + if(isSilentMonitor()) + { + sb.append(" SILENT MONITORING"); + } + sb.append(" TIME:").append(getTransmitTime()); + sb.append(" MULTIPLIER:").append(getTransmitMultiplier()); + return sb.toString(); + } + + /** + * Indicates if the target radio should not indicate to the user that the radio is being monitored. + */ + public boolean isSilentMonitor() + { + return getMessage().get(SILENT_MONITOR + getOffset()); + } + + /** + * Transmit time. + */ + public int getTransmitTime() + { + return getMessage().getInt(TRANSMIT_TIME, getOffset()); + } + + /** + * Multiplier for transmit time. + */ + public int getTransmitMultiplier() + { + return getMessage().getInt(TRANSMIT_MULTIPLIER, getOffset()); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RadioUnitMonitorCommandEnhanced.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RadioUnitMonitorCommandEnhanced.java new file mode 100644 index 000000000..a1825e0e1 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RadioUnitMonitorCommandEnhanced.java @@ -0,0 +1,202 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.Encryption; + +import java.util.ArrayList; +import java.util.List; + +/** + * Radio unit monitor command - enhanced format. Commands the target radio to initiate a group or unit-to-unit call to + * either the source address to or the talkgroup, either clear or encrypted + */ +public class RadioUnitMonitorCommandEnhanced extends MacStructure +{ + private static final int[] TARGET_ADDRESS = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31}; + private static final int[] TALKGROUP_ID = {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 int SM = 72; //Stealth Mode? + private static final int TG = 73; + private static final int[] TRANSMIT_TIME = {80, 81, 82, 83, 84, 85, 86, 87}; + private static final int[] KEY_ID = {88, 89, 90, 91, 92, 93, 94, 95}; + private static final int[] ALGORITHM_ID = {96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111}; + + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private TalkgroupIdentifier mTalkgroupId; + private TalkgroupIdentifier mSourceAddress; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public RadioUnitMonitorCommandEnhanced(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" CALL RADIO:").append(getSourceAddress()); + sb.append(" OR TALKGROUP:").append(getTalkgroupId()); + + if(isStealthMode()) + { + sb.append(" STEALTH MODE"); + } + + if(isTG()) + { + sb.append(" ?TG?"); + } + + long transmitTime = getTransmitTime(); + + if(transmitTime > 0) + { + sb.append(" TRANSMIT TIME:").append(transmitTime / 1000d).append("secs"); + } + + Encryption encryption = getEncryption(); + + if(encryption != Encryption.UNENCRYPTED) + { + sb.append(" USE ENCRYPTION:").append(encryption); + sb.append(" KEY:").append(getEncryptionKeyId()); + } + + return sb.toString(); + } + + /** + * To radio address + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * Talkgroup to call + */ + public TalkgroupIdentifier getTalkgroupId() + { + if(mTalkgroupId == null) + { + mTalkgroupId = APCO25FromTalkgroup.createGroup(getMessage().getInt(TALKGROUP_ID, getOffset())); + } + + return mTalkgroupId; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + /** + * No ICD ... anyone? + */ + public boolean isStealthMode() + { + return getMessage().get(SM + getOffset()); + } + + /** + * No ICD ... anyone? + */ + public boolean isTG() + { + return getMessage().get(TG + getOffset()); + } + + /** + * No ICD ... anyone? + * @return + */ + public long getTransmitTime() + { + return getMessage().getInt(TRANSMIT_TIME, getOffset()) * 100; //No ICD ... not sure if multiplier is correct + } + + /** + * Encryption key id to use for the callback + */ + public int getEncryptionKeyId() + { + return getMessage().getInt(KEY_ID, getOffset()); + } + + /** + * Encryption algorithm to use for the call-back + */ + public Encryption getEncryption() + { + return Encryption.fromValue(getMessage().getInt(ALGORITHM_ID, getOffset())); + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + mIdentifiers.add(getTalkgroupId()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RadioUnitMonitorCommandExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RadioUnitMonitorCommandExtended.java new file mode 100644 index 000000000..b16a42278 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RadioUnitMonitorCommandExtended.java @@ -0,0 +1,149 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FullyQualifiedIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Radio unit monitor command + */ +public class RadioUnitMonitorCommandExtended extends MacStructure +{ + private static final int[] TRANSMIT_TIME = {16, 17, 18, 19, 20, 21, 22, 23}; + private static final int SILENT_MONITOR = 24; //?? + private static final int[] TRANSMIT_MULTIPLIER = {30, 31}; + private static final int[] TARGET_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55}; + + private static final int[] SOURCE_WACN = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75}; + private static final int[] SOURCE_SYSTEM = {76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87}; + private static final int[] SOURCE_ADDRESS = {88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private APCO25FullyQualifiedIdentifier mSourceSuid; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public RadioUnitMonitorCommandExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceSuid()); + + if(isSilentMonitor()) + { + sb.append(" SILENT MONITORING"); + } + sb.append(" TIME:").append(getTransmitTime()); + sb.append(" MULTIPLIER:").append(getTransmitMultiplier()); + return sb.toString(); + } + + /** + * Indicates if the target radio should not indicate to the user that the radio is being monitored. + */ + public boolean isSilentMonitor() + { + return getMessage().get(SILENT_MONITOR + getOffset()); + } + + /** + * Transmit time. + */ + public int getTransmitTime() + { + return getMessage().getInt(TRANSMIT_TIME, getOffset()); + } + + /** + * Multiplier for transmit time. + */ + public int getTransmitMultiplier() + { + return getMessage().getInt(TRANSMIT_MULTIPLIER, getOffset()); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public APCO25FullyQualifiedIdentifier getSourceSuid() + { + if(mSourceSuid == null) + { + mSourceSuid = APCO25FullyQualifiedIdentifier.createFrom(getMessage().getInt(SOURCE_WACN, getOffset()), + getMessage().getInt(SOURCE_SYSTEM, getOffset()), getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceSuid; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceSuid()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RfssStatusBroadcastAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RfssStatusBroadcastAbbreviated.java new file mode 100644 index 000000000..13e7cc9c1 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RfssStatusBroadcastAbbreviated.java @@ -0,0 +1,179 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; +import io.github.dsheirer.module.decode.p25.identifier.APCO25System; +import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; +import io.github.dsheirer.module.decode.p25.identifier.channel.P25Channel; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * RFSS status broadcast - abbreviated format + */ +public class RfssStatusBroadcastAbbreviated extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] LRA = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int R = 18; + private static final int A = 19; + private static final int[] SYSTEM_ID = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + + private static final int[] RFSS_ID = {32, 33, 34, 35, 36, 37, 38, 39}; + private static final int[] SITE_ID = {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 List mIdentifiers; + private Identifier mLRA; + private Identifier mSystem; + private Identifier mRFSS; + private Identifier mSite; + private APCO25Channel mChannel; + private SystemServiceClass mSystemServiceClass; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public RfssStatusBroadcastAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" SYSTEM:").append(getSystem()); + sb.append(" RFSS:").append(getRFSS()); + sb.append(" SITE:").append(getSite()); + sb.append(" LRA:").append(getLRA()); + sb.append(" CHANNEL:").append(getChannel()); + sb.append(" SERVICES:").append(getSystemServiceClass().getServices()); + return sb.toString(); + } + + public Identifier getLRA() + { + if(mLRA == null) + { + mLRA = APCO25Lra.create(getMessage().getInt(LRA, getOffset())); + } + + return mLRA; + } + + public Identifier getRFSS() + { + if(mRFSS == null) + { + mRFSS = APCO25Rfss.create(getMessage().getInt(RFSS_ID, getOffset())); + } + + return mRFSS; + } + + public Identifier getSite() + { + if(mSite == null) + { + mSite = APCO25Site.create(getMessage().getInt(SITE_ID, getOffset())); + } + + return mSite; + } + + public Identifier getSystem() + { + if(mSystem == null) + { + mSystem = APCO25System.create(getMessage().getInt(SYSTEM_ID, getOffset())); + } + + return mSystem; + } + + /** + * Control channel. This will be a phase 1 control channel even though it's being broadcast on a Phase 2 channel. + */ + public APCO25Channel getChannel() + { + if(mChannel == null) + { + P25Channel channel = new P25Channel(getMessage().getInt(FREQUENCY_BAND, getOffset()), + getMessage().getInt(CHANNEL_NUMBER, getOffset())); + mChannel = new APCO25Channel(channel); + } + + return mChannel; + } + + public SystemServiceClass getSystemServiceClass() + { + if(mSystemServiceClass == null) + { + mSystemServiceClass = SystemServiceClass.create(getMessage().getInt(SERVICE_CLASS, getOffset())); + } + + return mSystemServiceClass; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getLRA()); + mIdentifiers.add(getSystem()); + mIdentifiers.add(getRFSS()); + mIdentifiers.add(getSite()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + return Collections.singletonList(getChannel()); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RfssStatusBroadcastExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RfssStatusBroadcastExtended.java new file mode 100644 index 000000000..81cf8be2d --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/RfssStatusBroadcastExtended.java @@ -0,0 +1,183 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Lra; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; +import io.github.dsheirer.module.decode.p25.identifier.APCO25System; +import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; +import io.github.dsheirer.module.decode.p25.identifier.channel.P25ExplicitChannel; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * RFSS status broadcast - extended format + */ +public class RfssStatusBroadcastExtended extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] LRA = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int R = 18; + private static final int A = 19; + private static final int[] SYSTEM_ID = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + + private static final int[] RFSS_ID = {32, 33, 34, 35, 36, 37, 38, 39}; + private static final int[] SITE_ID = {40, 41, 42, 43, 44, 45, 46, 47}; + private static final int[] TRANSMIT_FREQUENCY_BAND = {48, 49, 50, 51}; + private static final int[] TRANSMIT_CHANNEL_NUMBER = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; + private static final int[] RECEIVE_FREQUENCY_BAND = {64, 65, 66, 67}; + private static final int[] RECEIVE_CHANNEL_NUMBER = {68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}; + private static final int[] SERVICE_CLASS = {80, 81, 82, 83, 84, 85, 86, 87}; + + private List mIdentifiers; + private Identifier mLRA; + private Identifier mSystem; + private Identifier mRFSS; + private Identifier mSite; + private APCO25Channel mChannel; + private SystemServiceClass mSystemServiceClass; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public RfssStatusBroadcastExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" SYSTEM:").append(getSystem()); + sb.append(" RFSS:").append(getRFSS()); + sb.append(" SITE:").append(getSite()); + sb.append(" LRA:").append(getLRA()); + sb.append(" CHANNEL:").append(getChannel()); + sb.append(" SERVICES:").append(getSystemServiceClass().getServices()); + return sb.toString(); + } + + public Identifier getLRA() + { + if(mLRA == null) + { + mLRA = APCO25Lra.create(getMessage().getInt(LRA, getOffset())); + } + + return mLRA; + } + + public Identifier getRFSS() + { + if(mRFSS == null) + { + mRFSS = APCO25Rfss.create(getMessage().getInt(RFSS_ID, getOffset())); + } + + return mRFSS; + } + + public Identifier getSite() + { + if(mSite == null) + { + mSite = APCO25Site.create(getMessage().getInt(SITE_ID, getOffset())); + } + + return mSite; + } + + public Identifier getSystem() + { + if(mSystem == null) + { + mSystem = APCO25System.create(getMessage().getInt(SYSTEM_ID, getOffset())); + } + + return mSystem; + } + + /** + * Control channel. This will be a phase 1 channel, even though it's being broadcast on a Phase II channel. + */ + public APCO25Channel getChannel() + { + if(mChannel == null) + { + P25ExplicitChannel channel = new P25ExplicitChannel(getMessage().getInt(TRANSMIT_FREQUENCY_BAND, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER, getOffset()), + getMessage().getInt(RECEIVE_FREQUENCY_BAND, getOffset()), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER, getOffset())); + mChannel = new APCO25Channel(channel); + } + + return mChannel; + } + + public SystemServiceClass getSystemServiceClass() + { + if(mSystemServiceClass == null) + { + mSystemServiceClass = SystemServiceClass.create(getMessage().getInt(SERVICE_CLASS, getOffset())); + } + + return mSystemServiceClass; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getLRA()); + mIdentifiers.add(getSystem()); + mIdentifiers.add(getRFSS()); + mIdentifiers.add(getSite()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + return Collections.singletonList(getChannel()); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SNDCPDataChannelAnnouncementExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SNDCPDataChannelAnnouncementExplicit.java new file mode 100644 index 000000000..bfb5c7acb --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SNDCPDataChannelAnnouncementExplicit.java @@ -0,0 +1,178 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +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.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * SNDCP data channel announcement - explicit format + */ +public class SNDCPDataChannelAnnouncementExplicit extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int AUTONOMOUS_ACCESS_FLAG = 16; + private static final int REQUESTED_ACCESS_FLAG = 17; + private static final int[] TRANSMIT_FREQUENCY_BAND = {24, 25, 26, 27}; + private static final int[] TRANSMIT_CHANNEL_NUMBER = {28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; + private static final int[] RECEIVE_FREQUENCY_BAND = {40, 41, 42, 43}; + private static final int[] RECEIVE_CHANNEL_NUMBER = {44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55}; + private static final int[] DATA_ACCESS_CONTROL = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71}; + + private List mIdentifiers; + private APCO25Channel mChannel; + private TalkgroupIdentifier mTargetAddress; + private DataServiceOptions mServiceOptions; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public SNDCPDataChannelAnnouncementExplicit(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" CHAN:").append(getChannel()); + if(isAutonomousAccess() && isRequestedAccess()) + { + sb.append(" AUTONOMOUS/REQUESTED-ACCESS"); + } + else if(isAutonomousAccess()) + { + sb.append(" AUTONOMOUS-ACCESS"); + } + else if(isRequestedAccess()) + { + sb.append(" REQUESTED-ACCESS"); + } + sb.append(" DAC:").append(getDataAccessControl()); + sb.append(" ").append(getServiceOptions()); + return sb.toString(); + } + + public boolean isAutonomousAccess() + { + return getMessage().get(AUTONOMOUS_ACCESS_FLAG + getOffset()); + } + + public boolean isRequestedAccess() + { + return getMessage().get(REQUESTED_ACCESS_FLAG + getOffset()); + } + + + /** + * Voice channel service options + */ + public DataServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new DataServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * Channel + */ + public APCO25Channel getChannel() + { + if(mChannel == null) + { + if(isExplicitChannel()) + { + mChannel = APCO25ExplicitChannel.create(getMessage().getInt(TRANSMIT_FREQUENCY_BAND, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER, getOffset()), + getMessage().getInt(RECEIVE_FREQUENCY_BAND, getOffset()), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER, getOffset())); + } + else + { + mChannel = APCO25Channel.create(getMessage().getInt(TRANSMIT_FREQUENCY_BAND, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER, getOffset())); + } + } + + return mChannel; + } + + /** + * Indicates if the channel is an explicit channel, meaning that there are separate downlink + * and uplink channel numbers included. When false, the channel number is the same for both + * uplink and downlink. + * + * @return true if this is an explicit channel. + */ + private boolean isExplicitChannel() + { + return getMessage().getInt(RECEIVE_CHANNEL_NUMBER, getOffset()) != 4095; + } + + public int getDataAccessControl() + { + return getMessage().getInt(DATA_ACCESS_CONTROL, getOffset()); + } + + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannel()); + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SNDCPDataChannelGrant.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SNDCPDataChannelGrant.java new file mode 100644 index 000000000..abe8e6633 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SNDCPDataChannelGrant.java @@ -0,0 +1,143 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +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.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * SNDCP data channel grant + */ +public class SNDCPDataChannelGrant extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] TRANSMIT_FREQUENCY_BAND = {16, 17, 18, 19}; + private static final int[] TRANSMIT_CHANNEL_NUMBER = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] RECEIVE_FREQUENCY_BAND = {32, 33, 34, 35}; + private static final int[] RECEIVE_CHANNEL_NUMBER = {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 List mIdentifiers; + private APCO25Channel mChannel; + private TalkgroupIdentifier mTargetAddress; + private DataServiceOptions mServiceOptions; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public SNDCPDataChannelGrant(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" CHAN:").append(getChannel()); + sb.append(" ").append(getServiceOptions()); + return sb.toString(); + } + + /** + * Voice channel service options + */ + public DataServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new DataServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * Channel + */ + public APCO25Channel getChannel() + { + if(mChannel == null) + { + mChannel = APCO25ExplicitChannel.create(getMessage().getInt(TRANSMIT_FREQUENCY_BAND, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER, getOffset()), + getMessage().getInt(RECEIVE_FREQUENCY_BAND, getOffset()), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER, getOffset())); + } + + return mChannel; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannel()); + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SNDCPDataPageRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SNDCPDataPageRequest.java new file mode 100644 index 000000000..b3b9b74cd --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SNDCPDataPageRequest.java @@ -0,0 +1,109 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.DataServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * SNDCP data page request + */ +public class SNDCPDataPageRequest extends MacStructure +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] DATA_ACCESS_CONTROL = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] TARGET_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private DataServiceOptions mServiceOptions; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public SNDCPDataPageRequest(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" ").append(getServiceOptions()); + return sb.toString(); + } + + /** + * Voice channel service options + */ + public DataServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new DataServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SecondaryControlChannelBroadcastAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SecondaryControlChannelBroadcastAbbreviated.java new file mode 100644 index 000000000..19c0c631e --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SecondaryControlChannelBroadcastAbbreviated.java @@ -0,0 +1,183 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; +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.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; + +import java.util.ArrayList; +import java.util.List; + +/** + * Secondary control channel broadcast - abbreviated format + */ +public class SecondaryControlChannelBroadcastAbbreviated extends MacStructure 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[] SYSTEM_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[] SYSTEM_SERVICE_CLASS_B = {64, 65, 66, 67, 68, 69, 70, 71}; + + private Identifier mRfss; + private Identifier mSite; + private IChannelDescriptor mChannelA; + private IChannelDescriptor mChannelB; + private SystemServiceClass mSystemServiceClassA; + private SystemServiceClass mSystemServiceClassB; + private List mIdentifiers; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public SecondaryControlChannelBroadcastAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" RFSS:").append(getRfss()); + sb.append(" SITE:").append(getSite()); + sb.append(" CHAN A:").append(getChannelA()); + sb.append(" SERVICE OPTIONS:").append(getSystemServiceClassA()); + if(hasChannelB()) + { + sb.append(" CHAN B:").append(getChannelB()); + sb.append(" SERVICE OPTIONS:").append(getSystemServiceClassB()); + } + return sb.toString(); + } + + public Identifier getRfss() + { + if(mRfss == null) + { + mRfss = APCO25Rfss.create(getMessage().getInt(RFSS, getOffset())); + } + + return mRfss; + } + + public Identifier getSite() + { + if(mSite == null) + { + mSite = APCO25Site.create(getMessage().getInt(SITE, getOffset())); + } + + return mSite; + } + + public IChannelDescriptor getChannelA() + { + if(mChannelA == null) + { + mChannelA = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND_A, getOffset()), + getMessage().getInt(CHANNEL_NUMBER_A, getOffset())); + } + + return mChannelA; + } + + public SystemServiceClass getSystemServiceClassA() + { + if(mSystemServiceClassA == null) + { + mSystemServiceClassA = new SystemServiceClass(getMessage().getInt(SYSTEM_SERVICE_CLASS_A, getOffset())); + } + + return mSystemServiceClassA; + } + + private boolean hasChannelB() + { + return getMessage().getInt(CHANNEL_NUMBER_A, getOffset()) != getMessage().getInt(CHANNEL_NUMBER_B, getOffset()) && + getMessage().getInt(SYSTEM_SERVICE_CLASS_B, getOffset()) != 0; + } + + public IChannelDescriptor getChannelB() + { + if(hasChannelB() && mChannelB == null) + { + mChannelB = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND_B, getOffset()), + getMessage().getInt(CHANNEL_NUMBER_B, getOffset())); + } + + return mChannelB; + } + + public SystemServiceClass getSystemServiceClassB() + { + if(mSystemServiceClassB == null) + { + mSystemServiceClassB = new SystemServiceClass(getMessage().getInt(SYSTEM_SERVICE_CLASS_B, getOffset())); + } + + return mSystemServiceClassB; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getSite()); + mIdentifiers.add(getRfss()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannelA()); + + if(hasChannelB()) + { + channels.add(getChannelB()); + } + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SecondaryControlChannelBroadcastExplicit.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SecondaryControlChannelBroadcastExplicit.java new file mode 100644 index 000000000..86e24fffd --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SecondaryControlChannelBroadcastExplicit.java @@ -0,0 +1,145 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Rfss; +import io.github.dsheirer.module.decode.p25.identifier.APCO25Site; +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.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.SystemServiceClass; + +import java.util.ArrayList; +import java.util.List; + +/** + * Secondary control channel broadcast - explicit channel format + */ +public class SecondaryControlChannelBroadcastExplicit extends MacStructure 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[] TRANSMIT_FREQUENCY_BAND = {24, 25, 26, 27}; + private static final int[] TRANSMIT_CHANNEL_NUMBER = {28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; + private static final int[] RECEIVE_FREQUENCY_BAND = {40, 41, 42, 43}; + private static final int[] RECEIVE_CHANNEL_NUMBER = {44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55}; + private static final int[] SYSTEM_SERVICE_CLASS = {56, 57, 58, 59, 60, 61, 62, 63}; + + private Identifier mRfss; + private Identifier mSite; + private IChannelDescriptor mChannel; + private SystemServiceClass mSystemServiceClass; + private List mIdentifiers; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public SecondaryControlChannelBroadcastExplicit(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" RFSS:").append(getRfss()); + sb.append(" SITE:").append(getSite()); + sb.append(" CHAN A:").append(getChannel()); + sb.append(" SERVICE OPTIONS:").append(getSystemServiceClass()); + return sb.toString(); + } + + public Identifier getRfss() + { + if(mRfss == null) + { + mRfss = APCO25Rfss.create(getMessage().getInt(RFSS, getOffset())); + } + + return mRfss; + } + + public Identifier getSite() + { + if(mSite == null) + { + mSite = APCO25Site.create(getMessage().getInt(SITE, getOffset())); + } + + return mSite; + } + + public IChannelDescriptor getChannel() + { + if(mChannel == null) + { + mChannel = APCO25ExplicitChannel.create(getMessage().getInt(TRANSMIT_FREQUENCY_BAND, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER, getOffset()), + getMessage().getInt(RECEIVE_FREQUENCY_BAND, getOffset()), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER, getOffset())); + } + + return mChannel; + } + + public SystemServiceClass getSystemServiceClass() + { + if(mSystemServiceClass == null) + { + mSystemServiceClass = new SystemServiceClass(getMessage().getInt(SYSTEM_SERVICE_CLASS, getOffset())); + } + + return mSystemServiceClass; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getSite()); + mIdentifiers.add(getRfss()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannel()); + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/StatusQueryAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/StatusQueryAbbreviated.java new file mode 100644 index 000000000..ffc6d7c5b --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/StatusQueryAbbreviated.java @@ -0,0 +1,110 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Status query - abbreviated format + */ +public class StatusQueryAbbreviated extends MacStructure +{ + private static final int[] TARGET_ADDRESS = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31}; + private static final int[] SOURCE_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private TalkgroupIdentifier mSourceAddress; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public StatusQueryAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceAddress()); + return sb.toString(); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/StatusQueryExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/StatusQueryExtended.java new file mode 100644 index 000000000..2c8555016 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/StatusQueryExtended.java @@ -0,0 +1,114 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FullyQualifiedIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Status query - extended format + */ +public class StatusQueryExtended extends MacStructure +{ + private static final int[] TARGET_ADDRESS = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31}; + private static final int[] SOURCE_WACN = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51}; + private static final int[] SOURCE_SYSTEM = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; + private static final int[] SOURCE_ADDRESS = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private APCO25FullyQualifiedIdentifier mSourceSuid; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public StatusQueryExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceSuid()); + return sb.toString(); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public APCO25FullyQualifiedIdentifier getSourceSuid() + { + if(mSourceSuid == null) + { + mSourceSuid = APCO25FullyQualifiedIdentifier.createFrom(getMessage().getInt(SOURCE_WACN, getOffset()), + getMessage().getInt(SOURCE_SYSTEM, getOffset()), getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceSuid; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceSuid()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/StatusUpdateAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/StatusUpdateAbbreviated.java new file mode 100644 index 000000000..d6689abbc --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/StatusUpdateAbbreviated.java @@ -0,0 +1,140 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +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.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Status update - abbreviated format + */ +public class StatusUpdateAbbreviated extends MacStructure +{ + private static final int[] UNIT_STATUS = {16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] USER_STATUS = {24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] TARGET_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + private static final int[] SOURCE_ADDRESS = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79}; + + private List mIdentifiers; + private Identifier mUnitStatus; + private Identifier mUserStatus; + private TalkgroupIdentifier mTargetAddress; + private TalkgroupIdentifier mSourceAddress; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public StatusUpdateAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + 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; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + mIdentifiers.add(getUnitStatus()); + mIdentifiers.add(getUserStatus()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/StatusUpdateExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/StatusUpdateExtended.java new file mode 100644 index 000000000..9b41d2da4 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/StatusUpdateExtended.java @@ -0,0 +1,145 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +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.identifier.talkgroup.APCO25FullyQualifiedIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Status update - abbreviated format + */ +public class StatusUpdateExtended extends MacStructure +{ + private static final int[] UNIT_STATUS = {16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] USER_STATUS = {24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] TARGET_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + private static final int[] SOURCE_WACN = {56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75}; + private static final int[] SOURCE_SYSTEM = {76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87}; + private static final int[] SOURCE_ADDRESS = {88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111}; + + private List mIdentifiers; + private Identifier mUnitStatus; + private Identifier mUserStatus; + private TalkgroupIdentifier mTargetAddress; + private APCO25FullyQualifiedIdentifier mSourceSuid; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public StatusUpdateExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceSuid()); + 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; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public APCO25FullyQualifiedIdentifier getSourceSuid() + { + if(mSourceSuid == null) + { + mSourceSuid = APCO25FullyQualifiedIdentifier.createFrom(getMessage().getInt(SOURCE_WACN, getOffset()), + getMessage().getInt(SOURCE_SYSTEM, getOffset()), getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceSuid; + } + + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceSuid()); + mIdentifiers.add(getUnitStatus()); + mIdentifiers.add(getUserStatus()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SystemServiceBroadcast.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SystemServiceBroadcast.java new file mode 100644 index 000000000..2d12364f1 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/SystemServiceBroadcast.java @@ -0,0 +1,96 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.Service; + +import java.util.Collections; +import java.util.List; + +/** + * System services broadcast + */ +public class SystemServiceBroadcast extends MacStructure +{ + private static final int[] TWUID_VALIDITY = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] AVAILABLE_SERVICES = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39}; + private static final int[] SUPPORTED_SERVICES = {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[] REQUEST_PRIORITY_LEVEL = {64, 65, 66, 67, 68, 69, 70, 71}; + + private List mAvailableServices; + private List mSupportedServices; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public SystemServiceBroadcast(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" AVAILABLE SERVICES ").append(getAvailableServices()); + sb.append(" SUPPORTED SERVICES ").append(getSupportedServices()); + return sb.toString(); + } + + public List getAvailableServices() + { + if(mAvailableServices == null) + { + mAvailableServices = Service.getServices(getMessage().getInt(AVAILABLE_SERVICES, getOffset())); + } + + return mAvailableServices; + } + + public List getSupportedServices() + { + if(mSupportedServices == null) + { + mSupportedServices = Service.getServices(getMessage().getInt(SUPPORTED_SERVICES, getOffset())); + } + + return mSupportedServices; + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/TelephoneInterconnectAnswerRequest.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/TelephoneInterconnectAnswerRequest.java new file mode 100644 index 000000000..e33a04762 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/TelephoneInterconnectAnswerRequest.java @@ -0,0 +1,131 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.telephone.APCO25TelephoneNumber; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.Digit; + +import java.util.ArrayList; +import java.util.List; + +/** + * Telephone interconnect answer request + */ +public class TelephoneInterconnectAnswerRequest extends MacStructure +{ + 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 List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private Identifier mTelephoneNumber; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public TelephoneInterconnectAnswerRequest(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" TELEPHONE:").append(getTelephoneNumber()); + return sb.toString(); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * Telephone number + */ + public Identifier getTelephoneNumber() + { + if(mTelephoneNumber == null) + { + List digits = new ArrayList<>(); + digits.add(getMessage().getInt(DIGIT_1, getOffset())); + digits.add(getMessage().getInt(DIGIT_2, getOffset())); + digits.add(getMessage().getInt(DIGIT_3, getOffset())); + digits.add(getMessage().getInt(DIGIT_4, getOffset())); + digits.add(getMessage().getInt(DIGIT_5, getOffset())); + digits.add(getMessage().getInt(DIGIT_6, getOffset())); + digits.add(getMessage().getInt(DIGIT_7, getOffset())); + digits.add(getMessage().getInt(DIGIT_8, getOffset())); + digits.add(getMessage().getInt(DIGIT_9, getOffset())); + digits.add(getMessage().getInt(DIGIT_10, getOffset())); + + mTelephoneNumber = APCO25TelephoneNumber.createAny(Digit.decode(digits)); + } + + return mTelephoneNumber; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getTelephoneNumber()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/TelephoneInterconnectVoiceChannelUser.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/TelephoneInterconnectVoiceChannelUser.java new file mode 100644 index 000000000..532079ce8 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/TelephoneInterconnectVoiceChannelUser.java @@ -0,0 +1,132 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25AnyTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Telephone interconnect voice channel user + */ +public class TelephoneInterconnectVoiceChannelUser extends MacStructure +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] CALL_TIMER = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + private static final int[] SOURCE_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + + private List mIdentifiers; + private TalkgroupIdentifier mToOrFromAddress; + private VoiceServiceOptions mServiceOptions; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public TelephoneInterconnectVoiceChannelUser(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO/FROM:").append(getToOrFromAddress()); + + long timer = getCallTimer(); + + if(timer == 0) + { + sb.append(" TIMER:none"); + } + else + { + sb.append(" TIMER:").append(timer / 1000d).append("seconds"); + } + + sb.append(" ").append(getServiceOptions()); + + return sb.toString(); + } + + /** + * Voice channel service options + */ + public VoiceServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * Call timer in milliseconds. + * + * @return timer in milliseconds where a value of 0 indicates no timer. + */ + public long getCallTimer() + { + return getMessage().getInt(CALL_TIMER, getOffset()) * 100; //milliseconds + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getToOrFromAddress() + { + if(mToOrFromAddress == null) + { + mToOrFromAddress = APCO25AnyTalkgroup.create(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mToOrFromAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getToOrFromAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitRegistrationCommandAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitRegistrationCommandAbbreviated.java new file mode 100644 index 000000000..6a3f56752 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitRegistrationCommandAbbreviated.java @@ -0,0 +1,110 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unit registration command - abbreviated format + */ +public class UnitRegistrationCommandAbbreviated extends MacStructure +{ + private static final int[] TARGET_ADDRESS = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31}; + private static final int[] SOURCE_ADDRESS = {32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55}; + + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private TalkgroupIdentifier mSourceAddress; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public UnitRegistrationCommandAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceAddress()); + return sb.toString(); + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitAnswerRequestAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitAnswerRequestAbbreviated.java new file mode 100644 index 000000000..85634f985 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitAnswerRequestAbbreviated.java @@ -0,0 +1,127 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unit-to-unit answer request - abbreviated format + */ +public class UnitToUnitAnswerRequestAbbreviated extends MacStructure +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] TARGET_ADDRESS = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39}; + private static final int[] SOURCE_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 List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private TalkgroupIdentifier mSourceAddress; + private VoiceServiceOptions mServiceOptions; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public UnitToUnitAnswerRequestAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceAddress()); + sb.append(" ").append(getServiceOptions()); + return sb.toString(); + } + + /** + * Voice channel service options + */ + public VoiceServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitAnswerRequestExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitAnswerRequestExtended.java new file mode 100644 index 000000000..8ba43a5d8 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitAnswerRequestExtended.java @@ -0,0 +1,131 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FullyQualifiedIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unit-to-Unit answer request - extended format + */ +public class UnitToUnitAnswerRequestExtended extends MacStructure +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] TARGET_ADDRESS = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39}; + private static final int[] FULLY_QUALIFIED_SOURCE_WACN = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59}; + private static final int[] FULLY_QUALIFIED_SOURCE_SYSTEM = {60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71}; + private static final int[] FULLY_QUALIFIED_SOURCE_ID = {72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95}; + + private List mIdentifiers; + private VoiceServiceOptions mServiceOptions; + private TalkgroupIdentifier mTargetAddress; + private APCO25FullyQualifiedIdentifier mSourceSuid; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public UnitToUnitAnswerRequestExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceSuid()); + sb.append(" ").append(getServiceOptions()); + return sb.toString(); + } + + /** + * Voice channel service options + */ + public VoiceServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + public APCO25FullyQualifiedIdentifier getSourceSuid() + { + if(mSourceSuid == null) + { + int wacn = getMessage().getInt(FULLY_QUALIFIED_SOURCE_WACN, getOffset()); + int system = getMessage().getInt(FULLY_QUALIFIED_SOURCE_SYSTEM, getOffset()); + int id = getMessage().getInt(FULLY_QUALIFIED_SOURCE_ID, getOffset()); + + mSourceSuid = APCO25FullyQualifiedIdentifier.createFrom(wacn, system, id); + } + + return mSourceSuid; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceSuid()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelGrantAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelGrantAbbreviated.java new file mode 100644 index 000000000..4d62731fa --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelGrantAbbreviated.java @@ -0,0 +1,141 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; +import io.github.dsheirer.module.decode.p25.identifier.channel.P25P2Channel; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unit-to-unit voice channel grant - abbreviated format + */ +public class UnitToUnitVoiceChannelGrantAbbreviated extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] FREQUENCY_BAND = {8, 9, 10, 11}; + private static final int[] CHANNEL_NUMBER = {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] TARGET_ADDRESS = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39}; + private static final int[] SOURCE_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 List mIdentifiers; + private APCO25Channel mChannel; + private TalkgroupIdentifier mTargetAddress; + private TalkgroupIdentifier mSourceAddress; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public UnitToUnitVoiceChannelGrantAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceAddress()); + sb.append(" CHAN:").append(getChannel()); + return sb.toString(); + } + + /** + * Channel + */ + public APCO25Channel getChannel() + { + if(mChannel == null) + { + mChannel = new APCO25Channel(new P25P2Channel(getMessage().getInt(FREQUENCY_BAND, getOffset()), + getMessage().getInt(CHANNEL_NUMBER, getOffset()))); + } + + return mChannel; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannel()); + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelGrantExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelGrantExtended.java new file mode 100644 index 000000000..9aa3c1115 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelGrantExtended.java @@ -0,0 +1,146 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +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.APCO25FullyQualifiedIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unit-to-Unit voice channel grant - extended format + */ +public class UnitToUnitVoiceChannelGrantExtended extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] TRANSMIT_FREQUENCY_BAND = {8, 9, 10, 11}; + private static final int[] TRANSMIT_CHANNEL_NUMBER = {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] RECEIVE_FREQUENCY_BAND = {24, 25, 26, 27}; + private static final int[] RECEIVE_CHANNEL_NUMBER = {28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; + private static final int[] FULLY_QUALIFIED_SOURCE_WACN = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59}; + private static final int[] FULLY_QUALIFIED_SOURCE_SYSTEM = {60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71}; + private static final int[] FULLY_QUALIFIED_SOURCE_ID = {72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95}; + private static final int[] TARGET_ADDRESS = {96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119}; + + private APCO25Channel mChannel; + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private APCO25FullyQualifiedIdentifier mSourceSuid; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public UnitToUnitVoiceChannelGrantExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceSuid()); + sb.append(" CHAN:").append(getChannel()); + return sb.toString(); + } + + public APCO25Channel getChannel() + { + if(mChannel == null) + { + mChannel = APCO25ExplicitChannel.create(getMessage().getInt(TRANSMIT_FREQUENCY_BAND, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER, getOffset()), + getMessage().getInt(RECEIVE_FREQUENCY_BAND, getOffset()), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER, getOffset())); + } + + return mChannel; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + public APCO25FullyQualifiedIdentifier getSourceSuid() + { + if(mSourceSuid == null) + { + int wacn = getMessage().getInt(FULLY_QUALIFIED_SOURCE_WACN, getOffset()); + int system = getMessage().getInt(FULLY_QUALIFIED_SOURCE_SYSTEM, getOffset()); + int id = getMessage().getInt(FULLY_QUALIFIED_SOURCE_ID, getOffset()); + + mSourceSuid = APCO25FullyQualifiedIdentifier.createFrom(wacn, system, id); + } + + return mSourceSuid; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceSuid()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List descriptors = new ArrayList<>(); + descriptors.add(getChannel()); + return descriptors; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelGrantUpdateAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelGrantUpdateAbbreviated.java new file mode 100644 index 000000000..ffa099068 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelGrantUpdateAbbreviated.java @@ -0,0 +1,140 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.channel.APCO25Channel; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unit-to-unit voice channel grant update - abbreviated format + */ +public class UnitToUnitVoiceChannelGrantUpdateAbbreviated extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] FREQUENCY_BAND = {8, 9, 10, 11}; + private static final int[] CHANNEL_NUMBER = {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] TARGET_ADDRESS = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39}; + private static final int[] SOURCE_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 List mIdentifiers; + private APCO25Channel mChannel; + private TalkgroupIdentifier mTargetAddress; + private TalkgroupIdentifier mSourceAddress; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public UnitToUnitVoiceChannelGrantUpdateAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceAddress()); + sb.append(" CHAN:").append(getChannel()); + return sb.toString(); + } + + /** + * Channel + */ + public APCO25Channel getChannel() + { + if(mChannel == null) + { + mChannel = APCO25Channel.create(getMessage().getInt(FREQUENCY_BAND, getOffset()), + getMessage().getInt(CHANNEL_NUMBER, getOffset())); + } + + return mChannel; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List channels = new ArrayList<>(); + channels.add(getChannel()); + return channels; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelGrantUpdateExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelGrantUpdateExtended.java new file mode 100644 index 000000000..6df3d4f42 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelGrantUpdateExtended.java @@ -0,0 +1,147 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.channel.IChannelDescriptor; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +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.channel.P25P2ExplicitChannel; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FullyQualifiedIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase1.message.IFrequencyBandReceiver; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unit-to-Unit voice channel grant update - extended format + */ +public class UnitToUnitVoiceChannelGrantUpdateExtended extends MacStructure implements IFrequencyBandReceiver +{ + private static final int[] TRANSMIT_FREQUENCY_BAND = {8, 9, 10, 11}; + private static final int[] TRANSMIT_CHANNEL_NUMBER = {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + private static final int[] RECEIVE_FREQUENCY_BAND = {24, 25, 26, 27}; + private static final int[] RECEIVE_CHANNEL_NUMBER = {28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; + private static final int[] FULLY_QUALIFIED_SOURCE_WACN = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59}; + private static final int[] FULLY_QUALIFIED_SOURCE_SYSTEM = {60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71}; + private static final int[] FULLY_QUALIFIED_SOURCE_ID = {72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95}; + private static final int[] TARGET_ADDRESS = {96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119}; + + private APCO25Channel mChannel; + private List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private APCO25FullyQualifiedIdentifier mSourceSuid; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public UnitToUnitVoiceChannelGrantUpdateExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceSuid()); + sb.append(" CHAN:").append(getChannel()); + return sb.toString(); + } + + public APCO25Channel getChannel() + { + if(mChannel == null) + { + mChannel = new APCO25ExplicitChannel(new P25P2ExplicitChannel(getMessage().getInt(TRANSMIT_FREQUENCY_BAND, getOffset()), + getMessage().getInt(TRANSMIT_CHANNEL_NUMBER, getOffset()), + getMessage().getInt(RECEIVE_FREQUENCY_BAND, getOffset()), + getMessage().getInt(RECEIVE_CHANNEL_NUMBER, getOffset()))); + } + + return mChannel; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + public APCO25FullyQualifiedIdentifier getSourceSuid() + { + if(mSourceSuid == null) + { + int wacn = getMessage().getInt(FULLY_QUALIFIED_SOURCE_WACN, getOffset()); + int system = getMessage().getInt(FULLY_QUALIFIED_SOURCE_SYSTEM, getOffset()); + int id = getMessage().getInt(FULLY_QUALIFIED_SOURCE_ID, getOffset()); + + mSourceSuid = APCO25FullyQualifiedIdentifier.createFrom(wacn, system, id); + } + + return mSourceSuid; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceSuid()); + mIdentifiers.add(getChannel()); + } + + return mIdentifiers; + } + + @Override + public List getChannels() + { + List descriptors = new ArrayList<>(); + descriptors.add(getChannel()); + return descriptors; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelUserAbbreviated.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelUserAbbreviated.java new file mode 100644 index 000000000..e11de5c0f --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelUserAbbreviated.java @@ -0,0 +1,127 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unit-to-unit voice channel user - abbreviated format + */ +public class UnitToUnitVoiceChannelUserAbbreviated extends MacStructure +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] TARGET_ADDRESS = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39}; + private static final int[] SOURCE_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 List mIdentifiers; + private TalkgroupIdentifier mTargetAddress; + private TalkgroupIdentifier mSourceAddress; + private VoiceServiceOptions mServiceOptions; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public UnitToUnitVoiceChannelUserAbbreviated(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceAddress()); + sb.append(" ").append(getServiceOptions()); + return sb.toString(); + } + + /** + * Voice channel service options + */ + public VoiceServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelUserExtended.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelUserExtended.java new file mode 100644 index 000000000..fd60c9f56 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnitToUnitVoiceChannelUserExtended.java @@ -0,0 +1,150 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FromTalkgroup; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25FullyQualifiedIdentifier; +import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgroup; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.VoiceServiceOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unit-to-Unit voice channel user - extended format + */ +public class UnitToUnitVoiceChannelUserExtended extends MacStructure +{ + private static final int[] SERVICE_OPTIONS = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] TARGET_ADDRESS = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39}; + private static final int[] SOURCE_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[] FULLY_QUALIFIED_SOURCE_WACN = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83}; + private static final int[] FULLY_QUALIFIED_SOURCE_SYSTEM = {84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95}; + private static final int[] FULLY_QUALIFIED_SOURCE_ID = {96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119}; + + private List mIdentifiers; + private VoiceServiceOptions mServiceOptions; + private TalkgroupIdentifier mTargetAddress; + private TalkgroupIdentifier mSourceAddress; + private APCO25FullyQualifiedIdentifier mSourceSuid; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public UnitToUnitVoiceChannelUserExtended(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getOpcode()); + sb.append(" TO:").append(getTargetAddress()); + sb.append(" FM:").append(getSourceAddress()); + sb.append(" SUID:").append(getSourceSuid()); + sb.append(" ").append(getServiceOptions()); + return sb.toString(); + } + + /** + * Voice channel service options + */ + public VoiceServiceOptions getServiceOptions() + { + if(mServiceOptions == null) + { + mServiceOptions = new VoiceServiceOptions(getMessage().getInt(SERVICE_OPTIONS, getOffset())); + } + + return mServiceOptions; + } + + /** + * To Talkgroup + */ + public TalkgroupIdentifier getTargetAddress() + { + if(mTargetAddress == null) + { + mTargetAddress = APCO25ToTalkgroup.createIndividual(getMessage().getInt(TARGET_ADDRESS, getOffset())); + } + + return mTargetAddress; + } + + /** + * From Radio Unit + */ + public TalkgroupIdentifier getSourceAddress() + { + if(mSourceAddress == null) + { + mSourceAddress = APCO25FromTalkgroup.createIndividual(getMessage().getInt(SOURCE_ADDRESS, getOffset())); + } + + return mSourceAddress; + } + + public APCO25FullyQualifiedIdentifier getSourceSuid() + { + if(mSourceSuid == null) + { + int wacn = getMessage().getInt(FULLY_QUALIFIED_SOURCE_WACN, getOffset()); + int system = getMessage().getInt(FULLY_QUALIFIED_SOURCE_SYSTEM, getOffset()); + int id = getMessage().getInt(FULLY_QUALIFIED_SOURCE_ID, getOffset()); + + mSourceSuid = APCO25FullyQualifiedIdentifier.createFrom(wacn, system, id); + } + + return mSourceSuid; + } + + @Override + public List getIdentifiers() + { + if(mIdentifiers == null) + { + mIdentifiers = new ArrayList<>(); + mIdentifiers.add(getTargetAddress()); + mIdentifiers.add(getSourceAddress()); + mIdentifiers.add(getSourceSuid()); + } + + return mIdentifiers; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnknownStructure.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnknownStructure.java new file mode 100644 index 000000000..663f7c96d --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnknownStructure.java @@ -0,0 +1,59 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; + +import java.util.Collections; +import java.util.List; + +/** + * Unknown MAC Opcode Structure. + */ +public class UnknownStructure extends MacStructure +{ + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset bit index to the start of this structure + */ + public UnknownStructure(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } + + @Override + public String toString() + { + return getOpcode().toString(); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnknownVendorMessage.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnknownVendorMessage.java new file mode 100644 index 000000000..28834e236 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/message/mac/structure/UnknownVendorMessage.java @@ -0,0 +1,84 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.message.mac.structure; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacStructure; +import io.github.dsheirer.module.decode.p25.reference.Vendor; + +import java.util.Collections; +import java.util.List; + +/** + * Unknown Vendor Message + */ +public class UnknownVendorMessage extends MacStructure +{ + private static final int[] VENDOR = {8, 9, 10, 11, 12, 13, 14, 15}; + private static final int[] LENGTH = {18, 19, 20, 21, 22, 23}; + + /** + * Constructs the message + * + * @param message containing the message bits + * @param offset into the message for this structure + */ + public UnknownVendorMessage(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + /** + * Textual representation of this message + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append("MANUFACTURER MESSAGE VENDOR:").append(getVendor()); + sb.append(" LENGTH:").append(getMessageLength()); + sb.append(" MSG:").append(getMessage().getSubMessage(getOffset(), getMessage().size()).toHexString()); + + return sb.toString(); + } + + public Vendor getVendor() + { + return Vendor.fromValue(getMessage().getInt(VENDOR, getOffset())); + } + + /** + * Length of this message + */ + public int getMessageLength() + { + return getMessage().getInt(LENGTH, getOffset()); + } + + + @Override + public List getIdentifiers() + { + return Collections.emptyList(); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/AbstractSignalingTimeslot.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/AbstractSignalingTimeslot.java new file mode 100644 index 000000000..6105cdb67 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/AbstractSignalingTimeslot.java @@ -0,0 +1,78 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.timeslot; + +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.phase2.enumeration.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacMessage; + +import java.util.Collections; +import java.util.List; + +/** + * Abstract class for FACCH and SACCH signaling bearer messages + */ +public abstract class AbstractSignalingTimeslot extends Timeslot +{ + /** + * Constructs a scrambled signaling timeslot + * + * @param message with scrambled timeslot data + * @param dataUnitID for the timeslot + * @param scramblingSequence to unscramble the message + * @param timeslot for the message + * @param timestamp of the last transmitted bit + */ + protected AbstractSignalingTimeslot(CorrectedBinaryMessage message, DataUnitID dataUnitID, + BinaryMessage scramblingSequence, int timeslot, long timestamp) + { + super(message, dataUnitID, scramblingSequence, timeslot, timestamp); + } + + /** + * Constructs an un-scrambled signaling timeslot + * + * @param message that is un-scrambled + * @param dataUnitID for the timeslot + * @param timeslot for the message + * @param timestamp of the message + */ + protected AbstractSignalingTimeslot(CorrectedBinaryMessage message, DataUnitID dataUnitID, int timeslot, long timestamp) + { + super(message, dataUnitID, timeslot, timestamp); + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } + + + /** + * Access Encoded MAC Information (EMI) message(s) carried by the signalling timeslot + */ + public abstract List getMacMessages(); +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/AbstractVoiceTimeslot.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/AbstractVoiceTimeslot.java new file mode 100644 index 000000000..cc48a90fb --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/AbstractVoiceTimeslot.java @@ -0,0 +1,63 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.timeslot; + +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.phase2.enumeration.DataUnitID; + +import java.util.Collections; +import java.util.List; + +public abstract class AbstractVoiceTimeslot extends Timeslot +{ + protected AbstractVoiceTimeslot(CorrectedBinaryMessage message, DataUnitID dataUnitID, + BinaryMessage scramblingSequence, int timeslot, long timestamp) + { + super(message, dataUnitID, scramblingSequence, timeslot, timestamp); + } + + public abstract List getVoiceFrames(); + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append("TS").append(getTimeslot()); + sb.append(" ").append(getDataUnitID().toString()); + + for(int x = 0; x < getVoiceFrames().size(); x++) + { + sb.append(" ").append(x).append(":").append(getVoiceFrames().get(x).toHexString()); + } + return sb.toString(); + + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/FacchTimeslot.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/FacchTimeslot.java new file mode 100644 index 000000000..29f99ca4c --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/FacchTimeslot.java @@ -0,0 +1,290 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.timeslot; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.edac.ReedSolomon_63_35_29; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacMessage; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacMessageFactory; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.UnknownMacMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * Fast Associated Control CHannel (FACCH) timeslot carrying a S-OEMI Message + */ +public class FacchTimeslot extends AbstractSignalingTimeslot +{ + private final static Logger mLog = LoggerFactory.getLogger(FacchTimeslot.class); + + private static final int[] INFO_1 = {2,3,4,5,6,7}; + private static final int[] INFO_2 = {8,9,10,11,12,13}; + private static final int[] INFO_3 = {14,15,16,17,18,19}; + private static final int[] INFO_4 = {20,21,22,23,24,25}; + private static final int[] INFO_5 = {26,27,28,29,30,31}; + private static final int[] INFO_6 = {32,33,34,35,36,37}; + private static final int[] INFO_7 = {38,39,40,41,42,43}; + private static final int[] INFO_8 = {44,45,46,47,48,49}; + private static final int[] INFO_9 = {50,51,52,53,54,55}; + private static final int[] INFO_10 = {56,57,58,59,60,61}; + private static final int[] INFO_11 = {62,63,64,65,66,67}; + private static final int[] INFO_12 = {68,69,70,71,72,73}; //Gap for duid 74-75 + private static final int[] INFO_13 = {76,77,78,79,80,81}; + private static final int[] INFO_14 = {82,83,84,85,86,87}; + private static final int[] INFO_15 = {88,89,90,91,92,93}; + private static final int[] INFO_16 = {94,95,96,97,98,99}; + private static final int[] INFO_17 = {100,101,102,103,104,105}; + private static final int[] INFO_18 = {106,107,108,109,110,111}; + private static final int[] INFO_19 = {112,113,114,115,116,117}; + private static final int[] INFO_20 = {118,119,120,121,122,123}; + private static final int[] INFO_21 = {124,125,126,127,128,129}; + private static final int[] INFO_22 = {130,131,132,133,134,135}; + private static final int[] INFO_23 = {136,137,180,181,182,183}; //Gap for sync 138-179 + private static final int[] INFO_24 = {184,185,186,187,188,189}; + private static final int[] INFO_25 = {190,191,192,193,194,195}; + private static final int[] INFO_26 = {196,197,198,199,200,201}; + private static final int[] PARITY_1 = {202,203,204,205,206,207}; + private static final int[] PARITY_2 = {208,209,210,211,212,213}; + private static final int[] PARITY_3 = {214,215,216,217,218,219}; + private static final int[] PARITY_4 = {220,221,222,223,224,225}; + private static final int[] PARITY_5 = {226,227,228,229,230,231}; + private static final int[] PARITY_6 = {232,233,234,235,236,237}; + private static final int[] PARITY_7 = {238,239,240,241,242,243}; //Gap for duid 244-245 + private static final int[] PARITY_8 = {246,247,248,249,250,251}; + private static final int[] PARITY_9 = {252,253,254,255,256,257}; + private static final int[] PARITY_10 = {258,259,260,261,262,263}; + private static final int[] PARITY_11 = {264,265,266,267,268,269}; + private static final int[] PARITY_12 = {270,271,272,273,274,275}; + private static final int[] PARITY_13 = {276,277,278,279,280,281}; + private static final int[] PARITY_14 = {282,283,284,285,286,287}; + private static final int[] PARITY_15 = {288,289,290,291,292,293}; + private static final int[] PARITY_16 = {294,295,296,297,298,299}; + private static final int[] PARITY_17 = {300,301,302,303,304,305}; + private static final int[] PARITY_18 = {306,307,308,309,310,311}; + private static final int[] PARITY_19 = {312,313,314,315,316,317}; + + private List mMacMessages; + + /** + * Constructs a scrambled FACCH timeslot + * @param message containing 320 scrambled bits for the timeslot + * @param scramblingSequence to descramble the message + */ + public FacchTimeslot(CorrectedBinaryMessage message, BinaryMessage scramblingSequence, int timeslot, long timestamp) + { + super(message, DataUnitID.SCRAMBLED_FACCH, scramblingSequence, timeslot, timestamp); + } + + /** + * Constructs a un-scrambled FACCH timeslot + * @param message containing 320 scrambled bits for the timeslot + */ + public FacchTimeslot(CorrectedBinaryMessage message, int timeslot, long timestamp) + { + super(message, DataUnitID.UNSCRAMBLED_FACCH, timeslot, timestamp); + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append("TS").append(getTimeslot()); + + if(getDataUnitID() == DataUnitID.UNSCRAMBLED_FACCH) + { + sb.append(" FA-UN"); + sb.append(" ").append(getMacMessages().toString()); + } + else + { + sb.append(" FA-SC"); + sb.append(" SCRAMBLED:").append(getMessage().toHexString()); + } + + + return sb.toString(); + } + + /** + * Signaling Outbound Encoded MAC Information (S-OEMI) message(s) carried by this timeslot + */ + @Override + public List getMacMessages() + { + if(mMacMessages == null) + { + int[] input = new int[63]; + int[] output = new int[63]; + +// input[0] = 0; //Punctured +// input[1] = 0; //Punctured +// input[2] = 0; //Punctured +// input[3] = 0; //Punctured +// input[4] = 0; //Punctured +// input[5] = 0; //Punctured +// input[6] = 0; //Punctured +// input[7] = 0; //Punctured +// input[8] = 0; //Punctured + input[9] = getMessage().getInt(PARITY_19); + input[10] = getMessage().getInt(PARITY_18); + input[11] = getMessage().getInt(PARITY_17); + input[12] = getMessage().getInt(PARITY_16); + input[13] = getMessage().getInt(PARITY_15); + input[14] = getMessage().getInt(PARITY_14); + input[15] = getMessage().getInt(PARITY_13); + input[16] = getMessage().getInt(PARITY_12); + input[17] = getMessage().getInt(PARITY_11); + input[18] = getMessage().getInt(PARITY_10); + input[19] = getMessage().getInt(PARITY_9); + input[20] = getMessage().getInt(PARITY_8); + input[21] = getMessage().getInt(PARITY_7); + input[22] = getMessage().getInt(PARITY_6); + input[23] = getMessage().getInt(PARITY_5); + input[24] = getMessage().getInt(PARITY_4); + input[25] = getMessage().getInt(PARITY_3); + input[26] = getMessage().getInt(PARITY_2); + input[27] = getMessage().getInt(PARITY_1); + input[28] = getMessage().getInt(INFO_26); + input[29] = getMessage().getInt(INFO_25); + input[30] = getMessage().getInt(INFO_24); + input[27] = getMessage().getInt(INFO_23); + input[32] = getMessage().getInt(INFO_22); + input[33] = getMessage().getInt(INFO_21); + input[34] = getMessage().getInt(INFO_20); + input[35] = getMessage().getInt(INFO_19); + input[36] = getMessage().getInt(INFO_18); + input[37] = getMessage().getInt(INFO_17); + input[38] = getMessage().getInt(INFO_16); + input[39] = getMessage().getInt(INFO_15); + input[40] = getMessage().getInt(INFO_14); + input[41] = getMessage().getInt(INFO_13); + input[42] = getMessage().getInt(INFO_12); + input[43] = getMessage().getInt(INFO_11); + input[44] = getMessage().getInt(INFO_10); + input[45] = getMessage().getInt(INFO_9); + input[46] = getMessage().getInt(INFO_8); + input[47] = getMessage().getInt(INFO_7); + input[48] = getMessage().getInt(INFO_6); + input[49] = getMessage().getInt(INFO_5); + input[50] = getMessage().getInt(INFO_4); + input[51] = getMessage().getInt(INFO_3); + input[52] = getMessage().getInt(INFO_2); + input[53] = getMessage().getInt(INFO_1); +// input[54] = 0; //Shortened +// input[55] = 0; //Shortened +// input[56] = 0; //Shortened +// input[57] = 0; //Shortened +// input[58] = 0; //Shortened +// input[59] = 0; //Shortened +// input[60] = 0; //Shortened +// input[61] = 0; //Shortened +// input[62] = 0; //Shortened + + //Reed-Solomon(45,26,20) code protects the SOEMI word. Maximum correctable errors are: 13 (53 - 26 / 2) + ReedSolomon_63_35_29 reedSolomon_63_35_29 = new ReedSolomon_63_35_29(13); + + boolean irrecoverableErrors; + + try + { + irrecoverableErrors = reedSolomon_63_35_29.decode(input, output); + } + catch(Exception e) + { + irrecoverableErrors = true; + mLog.error("Error", e); + } + + CorrectedBinaryMessage binaryMessage = new CorrectedBinaryMessage(156); + + int pointer = 0; + + for(int x = 53; x >= 28; x--) + { + if(output[x] != -1) + { + binaryMessage.load(pointer, 6, output[x]); + } + + pointer += 6; + } + + mMacMessages = MacMessageFactory.create(getTimeslot(), getDataUnitID(), binaryMessage, getTimestamp()); + + if(irrecoverableErrors) + { + mMacMessages.clear(); + MacMessage macMessage = new UnknownMacMessage(getTimeslot(), getDataUnitID(), binaryMessage, getTimestamp()); + macMessage.setValid(false); + mMacMessages.add(macMessage); + } + else + { + //If we corrected any bit errors, update the original message with the bit error count + for(int x = 9; x <= 53; x++) + { + if(output[x] != input[x]) + { + binaryMessage.incrementCorrectedBitCount(Integer.bitCount((output[x] ^ input[x]))); + } + } + } + + } + + return mMacMessages; + } + + public static void main(String[] args) + { +// String raw = "575D57F7FFD8000000000000000030000000000000003FD55DDF5F500082919EB24B903F6A5B0BF9831985D29B"; + String raw = "575D57F7FFD8010020000000000030000000000000003FD55DDF5F500082919EB24B903F6A5B0BF9831985D29B"; + CorrectedBinaryMessage m = new CorrectedBinaryMessage(360); + + int pointer = 0; + + for(int x = 0; x < raw.length(); x += 2) + { + String braw = raw.substring(x, x + 2); + int parsed = Integer.parseInt(braw, 16); + m.load(pointer, 8, parsed); + pointer += 8; + } + + mLog.debug(" IN:" + raw); + mLog.debug("OUT:" + m.toHexString()); + + FacchTimeslot facch = new FacchTimeslot(m, 0, System.currentTimeMillis()); + + List macs = facch.getMacMessages(); + + for(MacMessage mac: macs) + { + mLog.debug(mac.toString()); + } + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/LinearFeedbackShiftRegister.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/LinearFeedbackShiftRegister.java new file mode 100644 index 000000000..06b1e0d13 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/LinearFeedbackShiftRegister.java @@ -0,0 +1,155 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.timeslot; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.bits.BitSetFullException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * APCO-25 Phase II Linear Feedback Shift Register for generating the scrambling sequence for descrambling + * a Phase II inbound or outbound channel. + */ +public class LinearFeedbackShiftRegister +{ + private final static Logger mLog = LoggerFactory.getLogger(LinearFeedbackShiftRegister.class); + + private static long MASK = 0xFFFFFFFFFFFl; + private static long TAP_43 = (1l << 43); + private static long TAP_33 = (1l << 33); + private static long TAP_19 = (1l << 19); + private static long TAP_14 = (1l << 14); + private static long TAP_8 = (1l << 8); + private static long TAP_3 = (1l << 3); + + private boolean mCurrentOutput; + private long mRegisters; + private int mWacn; + private int mSystem; + private int mNac; + + /** + * Constructs an APCO25 Phase II external LFSR generator equivalent to + * polynomial G(x)=x44 + x40 + x35 + x29 + x24 + x10 + x0 as defined in TIA-102.BBAC paragraph 7.2.5. + */ + public LinearFeedbackShiftRegister() + { + } + + public void updateSeed(int wacn, int system, int nac) + { + mWacn = wacn; + mSystem = system; + mNac = nac; + + int temp = 0xFFFFF & 1; + long tempShift = temp << 24; + + mRegisters = (long)(0xFFFFF & wacn) << 24; + mRegisters += (0xFFF & system) << 12; + mRegisters += (0xFFF & nac); + + if(mRegisters == 0) + { + mRegisters = 0xFFFFFFFFFFFl; + } + + mCurrentOutput = getTap(TAP_43); + } + + /** + * Indicates if the shift register is currently configured for the argument values (and doesn't need updating). + * + * @param wacn value + * @param system value + * @param nac value + * @return true if the argument values match the current shift register configuration + */ + public boolean isCurrent(int wacn, int system, int nac) + { + return mWacn == wacn && mSystem == system && mNac == nac; + } + + /** + * Generates a 4320 bit (de)scrambling sequence for APCO25 Phase II channel superframe. + * + * @param wacn for the network from the Network Status Broadcast message. + * @param system for the network from the Network Status Broadcast message. + * @param nac or color code for the network from the Network Status Broadcast message. + * @return scrambling sequence in a binary message + */ + public BinaryMessage generateScramblingSequence(int wacn, int system, int nac) + { + updateSeed(wacn, system, nac); + + BinaryMessage sequence = new BinaryMessage(4320); + + try + { + for(int x = 0; x < 4320; x++) + { + sequence.add(next()); + } + } + catch(BitSetFullException e) + { + //This shouldn't happen + } + + return sequence; + } + + /** + * Provides the next output bit from the LFSR + */ + public boolean next() + { + boolean retVal = getTap(TAP_43); + + boolean feedback = retVal; + + feedback ^= getTap(TAP_33); + feedback ^= getTap(TAP_19); + feedback ^= getTap(TAP_14); + feedback ^= getTap(TAP_8); + feedback ^= getTap(TAP_3); + mRegisters <<= 1; + mRegisters &= MASK; + + if(feedback) + { + mRegisters++; + } + + return retVal; + } + + /** + * Provides the boolean value of the specified tap position + */ + private boolean getTap(long tap) + { + return (mRegisters & tap) == tap; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/SacchTimeslot.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/SacchTimeslot.java new file mode 100644 index 000000000..f707e613b --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/SacchTimeslot.java @@ -0,0 +1,270 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.timeslot; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.edac.ReedSolomon_63_35_29; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacMessage; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.MacMessageFactory; +import io.github.dsheirer.module.decode.p25.phase2.message.mac.UnknownMacMessage; + +import java.util.List; + +/** + * Slow Associated Control CHannel (SACCH) timeslot carrying an I-OEMI message + */ +public class SacchTimeslot extends AbstractSignalingTimeslot +{ + private static final int[] INFO_1 = {2, 3, 4, 5, 6, 7}; + private static final int[] INFO_2 = {8, 9, 10, 11, 12, 13}; + private static final int[] INFO_3 = {14, 15, 16, 17, 18, 19}; + private static final int[] INFO_4 = {20, 21, 22, 23, 24, 25}; + private static final int[] INFO_5 = {26, 27, 28, 29, 30, 31}; + private static final int[] INFO_6 = {32, 33, 34, 35, 36, 37}; + private static final int[] INFO_7 = {38, 39, 40, 41, 42, 43}; + private static final int[] INFO_8 = {44, 45, 46, 47, 48, 49}; + private static final int[] INFO_9 = {50, 51, 52, 53, 54, 55}; + private static final int[] INFO_10 = {56, 57, 58, 59, 60, 61}; + private static final int[] INFO_11 = {62, 63, 64, 65, 66, 67}; + private static final int[] INFO_12 = {68, 69, 70, 71, 72, 73}; //Gap for duid 114-115 + private static final int[] INFO_13 = {76, 77, 78, 79, 80, 81}; + private static final int[] INFO_14 = {82, 83, 84, 85, 86, 87}; + private static final int[] INFO_15 = {88, 89, 90, 91, 92, 93}; + private static final int[] INFO_16 = {94, 95, 96, 97, 98, 99}; + private static final int[] INFO_17 = {100, 101, 102, 103, 104, 105}; + private static final int[] INFO_18 = {106, 107, 108, 109, 110, 111}; + private static final int[] INFO_19 = {112, 113, 114, 115, 116, 117}; + private static final int[] INFO_20 = {118, 119, 120, 121, 122, 123}; + private static final int[] INFO_21 = {124, 125, 126, 127, 128, 129}; + private static final int[] INFO_22 = {130, 131, 132, 133, 134, 135}; + private static final int[] INFO_23 = {136, 137, 138, 139, 140, 141}; + private static final int[] INFO_24 = {142, 143, 144, 145, 146, 147}; + private static final int[] INFO_25 = {148, 149, 150, 151, 152, 153}; + private static final int[] INFO_26 = {154, 155, 156, 157, 158, 159}; + private static final int[] INFO_27 = {160, 161, 162, 163, 164, 165}; + private static final int[] INFO_28 = {166, 167, 168, 169, 170, 171}; + private static final int[] INFO_29 = {172, 173, 174, 175, 176, 177}; + private static final int[] INFO_30 = {178, 179, 180, 181, 182, 183}; + private static final int[] PARITY_1 = {184, 185, 186, 187, 188, 189}; + private static final int[] PARITY_2 = {190, 191, 192, 193, 194, 195}; + private static final int[] PARITY_3 = {196, 197, 198, 199, 200, 201}; + private static final int[] PARITY_4 = {202, 203, 204, 205, 206, 207}; + private static final int[] PARITY_5 = {208, 209, 210, 211, 212, 213}; + private static final int[] PARITY_6 = {214, 215, 216, 217, 218, 219}; + private static final int[] PARITY_7 = {220, 221, 222, 223, 224, 225}; + private static final int[] PARITY_8 = {226, 227, 228, 229, 230, 231}; + private static final int[] PARITY_9 = {232, 233, 234, 235, 236, 237}; + private static final int[] PARITY_10 = {238, 239, 240, 241, 242, 243}; //Gap for duid 284-285 + private static final int[] PARITY_11 = {246, 247, 248, 249, 250, 251}; + private static final int[] PARITY_12 = {252, 253, 254, 255, 256, 257}; + private static final int[] PARITY_13 = {258, 259, 260, 261, 262, 263}; + private static final int[] PARITY_14 = {264, 265, 266, 267, 268, 269}; + private static final int[] PARITY_15 = {270, 271, 272, 273, 274, 275}; + private static final int[] PARITY_16 = {276, 277, 278, 279, 280, 281}; + private static final int[] PARITY_17 = {282, 283, 284, 285, 286, 287}; + private static final int[] PARITY_18 = {288, 289, 290, 291, 292, 293}; + private static final int[] PARITY_19 = {294, 295, 296, 297, 298, 299}; + private static final int[] PARITY_20 = {300, 301, 302, 303, 304, 305}; + private static final int[] PARITY_21 = {306, 307, 308, 309, 310, 311}; + private static final int[] PARITY_22 = {312, 313, 314, 315, 316, 317}; + + private List mMacMessages; + + /** + * Constructs a scrambled SACCH timeslot + * + * @param message containing 320 scrambled bits for the timeslot + * @param scramblingSequence to descramble the message + * @param timeslot of the message + * @param timestamp of the message + */ + public SacchTimeslot(CorrectedBinaryMessage message, BinaryMessage scramblingSequence, int timeslot, + long timestamp) + { + super(message, DataUnitID.SCRAMBLED_SACCH, scramblingSequence, timeslot, timestamp); + } + + /** + * Constructs an un-scrambled SACCH timeslot + * + * @param message containing 320 scrambled bits for the timeslot + * @param timeslot of the message + * @param timestamp of the message + */ + public SacchTimeslot(CorrectedBinaryMessage message, int timeslot, long timestamp) + { + super(message, DataUnitID.UNSCRAMBLED_SACCH, timeslot, timestamp); + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append("TS").append(getTimeslot()); + + if(getDataUnitID() == DataUnitID.UNSCRAMBLED_SACCH) + { + sb.append(" SA-UN"); + sb.append(" ").append(getMacMessages().toString()); + } + else + { + sb.append(" SA-SC"); + sb.append(" ").append(getMacMessages().toString()); + } + + + return sb.toString(); + } + + /** + * Information Outbound Encoded MAC Information (I-OEMI) message(s) carried by this timeslot + */ + @Override + public List getMacMessages() + { + if(mMacMessages == null) + { + int[] input = new int[63]; + int[] output = new int[63]; + +// input[0] = 0; //Punctured +// input[1] = 0; //Punctured +// input[2] = 0; //Punctured +// input[3] = 0; //Punctured +// input[4] = 0; //Punctured +// input[5] = 0; //Punctured + input[6] = getMessage().getInt(PARITY_22); + input[7] = getMessage().getInt(PARITY_21); + input[8] = getMessage().getInt(PARITY_20); + input[9] = getMessage().getInt(PARITY_19); + input[10] = getMessage().getInt(PARITY_18); + input[11] = getMessage().getInt(PARITY_17); + input[12] = getMessage().getInt(PARITY_16); + input[13] = getMessage().getInt(PARITY_15); + input[14] = getMessage().getInt(PARITY_14); + input[15] = getMessage().getInt(PARITY_13); + input[16] = getMessage().getInt(PARITY_12); + input[17] = getMessage().getInt(PARITY_11); + input[18] = getMessage().getInt(PARITY_10); + input[19] = getMessage().getInt(PARITY_9); + input[20] = getMessage().getInt(PARITY_8); + input[21] = getMessage().getInt(PARITY_7); + input[22] = getMessage().getInt(PARITY_6); + input[23] = getMessage().getInt(PARITY_5); + input[24] = getMessage().getInt(PARITY_4); + input[25] = getMessage().getInt(PARITY_3); + input[26] = getMessage().getInt(PARITY_2); + input[27] = getMessage().getInt(PARITY_1); + input[28] = getMessage().getInt(INFO_30); + input[29] = getMessage().getInt(INFO_29); + input[30] = getMessage().getInt(INFO_28); + input[31] = getMessage().getInt(INFO_27); + input[32] = getMessage().getInt(INFO_26); + input[33] = getMessage().getInt(INFO_25); + input[34] = getMessage().getInt(INFO_24); + input[35] = getMessage().getInt(INFO_23); + input[36] = getMessage().getInt(INFO_22); + input[37] = getMessage().getInt(INFO_21); + input[38] = getMessage().getInt(INFO_20); + input[39] = getMessage().getInt(INFO_19); + input[40] = getMessage().getInt(INFO_18); + input[41] = getMessage().getInt(INFO_17); + input[42] = getMessage().getInt(INFO_16); + input[43] = getMessage().getInt(INFO_15); + input[44] = getMessage().getInt(INFO_14); + input[45] = getMessage().getInt(INFO_13); + input[46] = getMessage().getInt(INFO_12); + input[47] = getMessage().getInt(INFO_11); + input[48] = getMessage().getInt(INFO_10); + input[49] = getMessage().getInt(INFO_9); + input[50] = getMessage().getInt(INFO_8); + input[51] = getMessage().getInt(INFO_7); + input[52] = getMessage().getInt(INFO_6); + input[53] = getMessage().getInt(INFO_5); + input[54] = getMessage().getInt(INFO_4); + input[55] = getMessage().getInt(INFO_3); + input[56] = getMessage().getInt(INFO_2); + input[57] = getMessage().getInt(INFO_1); +// input[58] = 0; //Shortened +// input[59] = 0; //Shortened +// input[60] = 0; //Shortened +// input[61] = 0; //Shortened +// input[62] = 0; //Shortened + + //Reed-Solomon(52,30,23) code protects the IOEMI word. Maximum correctable errors are: 14 (58 - 30 / 2) + ReedSolomon_63_35_29 reedSolomon_63_35_29 = new ReedSolomon_63_35_29(14); + + boolean irrecoverableErrors; + + try + { + irrecoverableErrors = reedSolomon_63_35_29.decode(input, output); + } + catch(Exception e) + { + irrecoverableErrors = true; + } + + CorrectedBinaryMessage binaryMessage = new CorrectedBinaryMessage(180); + + int pointer = 0; + + for(int x = 57; x >= 28; x--) + { + if(output[x] != -1) + { + binaryMessage.load(pointer, 6, output[x]); + } + + pointer += 6; + } + + mMacMessages = MacMessageFactory.create(getTimeslot(), getDataUnitID(), binaryMessage, getTimestamp()); + + if(irrecoverableErrors) + { + mMacMessages.clear(); + MacMessage macMessage = new UnknownMacMessage(getTimeslot(), getDataUnitID(), binaryMessage, getTimestamp()); + macMessage.setValid(false); + mMacMessages.add(macMessage); + } + else + { + //If we corrected any bit errors, update the original message with the bit error count + for(int x = 0; x <= 57; x++) + { + if(output[x] != input[x]) + { + binaryMessage.incrementCorrectedBitCount(Integer.bitCount((output[x] ^ input[x]))); + } + } + } + + } + + return mMacMessages; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/ScramblingSequence.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/ScramblingSequence.java new file mode 100644 index 000000000..73d9adee2 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/ScramblingSequence.java @@ -0,0 +1,98 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.timeslot; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * APCO-25 Phase II scrambling sequence utility that provides scrambling sequence snippets for each of the 12 timeslots + * in a 12-timeslot super frame. + */ +public class ScramblingSequence +{ + private final static Logger mLog = LoggerFactory.getLogger(ScramblingSequence.class); + + private LinearFeedbackShiftRegister mShiftRegister = new LinearFeedbackShiftRegister(); + private List mScramblingSegments = new ArrayList<>(); + + /** + * Constructs an instance + */ + public ScramblingSequence() + { + for(int x = 0; x < 12; x++) + { + mScramblingSegments.add(new BinaryMessage(320)); + } + } + + /** + * Updates this scrambling sequence with the specified seed parameters + */ + public void update(ScrambleParameters parameters) + { + update(parameters.getWACN(), parameters.getSystem(), parameters.getNAC()); + } + + /** + * Updates this scrambling sequence with the specified parameters from the Network Broadcast Status message and + * generates 12 x 320-bit scrambling sequences for each of the superframe's 12 timeslots. + */ + public void update(int wacn, int system, int nac) + { + if(!mShiftRegister.isCurrent(wacn, system, nac)) + { + mScramblingSegments.clear(); + + BinaryMessage scramblingSequence = mShiftRegister.generateScramblingSequence(wacn, system, nac); + + //Note: the scrambling sequence starts at halfway through the first ISCH of the superframe, so we start + //chopping the LFSR sequence using 320 of each 360 bits starting at bit 20 of 40 of the first ISCH. + for(int x = 20; x < 4320; x += 360) + { + mScramblingSegments.add(scramblingSequence.getSubMessage(x, x + 320)); + } + } + } + + /** + * Accesses the scrambling sequence for the specified timeslot index + * @param timeslot 0 - 11 + * @return scrambling sequence (320-bits) for the specified timeslot + */ + public BinaryMessage getTimeslotSequence(int timeslot) + { + if(0 <= timeslot && timeslot <= 11) + { + return mScramblingSegments.get(timeslot); + } + + throw new IllegalArgumentException("Unrecognized timeslot index: " + timeslot); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/Timeslot.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/Timeslot.java new file mode 100644 index 000000000..867cdf251 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/Timeslot.java @@ -0,0 +1,103 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.timeslot; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID; +import io.github.dsheirer.module.decode.p25.phase2.message.P25P2Message; + +/** + * Base timeslot class. + */ +public abstract class Timeslot extends P25P2Message +{ + public static final int[] DATA_UNIT_ID = {0,1,74,75,244,245,318,319}; + private CorrectedBinaryMessage mMessage; + private DataUnitID mDataUnitID; + private int mTimeslot; + + /** + * Constructs a scrambled timeslot instance and automatically descrambles the transmitted bits. + * @param message containing transmitted bits and bit error count + * @param dataUnitID that identifies this timeslot + * @param scramblingSequence to descramble this timeslot + * @param timeslot or timeslot 0 or 1 + * @param timestamp the message was received + */ + protected Timeslot(CorrectedBinaryMessage message, DataUnitID dataUnitID, BinaryMessage scramblingSequence, + int timeslot, long timestamp) + { + this(message, dataUnitID, timeslot, timestamp); + getMessage().xor(scramblingSequence); + } + + /** + * Constructs an unscrambled timeslot instance. + * @param message containing transmitted bits and bit error count + * @param dataUnitID that identifies this timeslot + * @param timeslot or timeslot 0 or 1 + * @param timestamp the message was received + */ + protected Timeslot(CorrectedBinaryMessage message, DataUnitID dataUnitID, int timeslot, long timestamp) + { + super(timestamp); + mMessage = message; + mDataUnitID = dataUnitID; + mTimeslot = timeslot; + } + + protected CorrectedBinaryMessage getMessage() + { + return mMessage; + } + + public DataUnitID getDataUnitID() + { + return mDataUnitID; + } + + /** + * Timeslot + * @return channel number (either Channel 0 or Channel 1) + */ + public int getTimeslot() + { + return mTimeslot; + } + + /** + * Lookup the Data Unit ID for this timeslot + * @param message containing a 320-bit timeslot frame with interleaved 8-bit duid value. + * @return data unit id or the id with the closest hamming distance to the decoded value. + */ + public static DataUnitID getDuid(CorrectedBinaryMessage message) + { + return DataUnitID.fromEncodedValue(message.getInt(DATA_UNIT_ID)); + } + + public String toString() + { + return getDataUnitID().toString(); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/TimeslotFactory.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/TimeslotFactory.java new file mode 100644 index 000000000..14cd137e2 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/TimeslotFactory.java @@ -0,0 +1,67 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.timeslot; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID; + +/** + * Timeslot factory. Constructs timeslot parsing implementations according to the timeslot's data unit ID + */ +public class TimeslotFactory +{ + /** + * Creates a timeslot parser instance + * + * @param message containing 320-bit timeslot data + * @param scramblingSequence to unscramble the transmitted message + * @param timeslot to retrieve + * @param timestamp for the message + * @return timeslot parser + */ + public static Timeslot getTimeslot(CorrectedBinaryMessage message, BinaryMessage scramblingSequence, + int timeslot, long timestamp) + { + DataUnitID dataUnitID = Timeslot.getDuid(message); + + switch(dataUnitID) + { + case VOICE_4: + return new Voice4Timeslot(message, scramblingSequence, timeslot, timestamp); + case VOICE_2: + return new Voice2Timeslot(message, scramblingSequence, timeslot, timestamp); + case SCRAMBLED_FACCH: + return new FacchTimeslot(message, scramblingSequence, timeslot, timestamp); + case SCRAMBLED_SACCH: + return new SacchTimeslot(message, scramblingSequence, timeslot, timestamp); + case UNSCRAMBLED_FACCH: + return new FacchTimeslot(message, timeslot, timestamp); + case UNSCRAMBLED_SACCH: + return new SacchTimeslot(message, timeslot, timestamp); + case UNKNOWN: + default: + return new UnknownTimeslot(message, timeslot, timestamp); + } + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/UnknownTimeslot.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/UnknownTimeslot.java new file mode 100644 index 000000000..2c3dd0ad5 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/UnknownTimeslot.java @@ -0,0 +1,44 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.timeslot; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID; + +import java.util.Collections; +import java.util.List; + +public class UnknownTimeslot extends Timeslot +{ + public UnknownTimeslot(CorrectedBinaryMessage message, int timeslot, long timestamp) + { + super(message, DataUnitID.VOICE_2, timeslot, timestamp); + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/Voice2Timeslot.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/Voice2Timeslot.java new file mode 100644 index 000000000..350505940 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/Voice2Timeslot.java @@ -0,0 +1,93 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.timeslot; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID; + +import java.util.ArrayList; +import java.util.List; + +/** + * Timeslot containing two voice frames and Encryption Sync Signalling (ESS-A) fragment. + */ +public class Voice2Timeslot extends AbstractVoiceTimeslot +{ + private static final int FRAME_LENGTH = 72; + private static final int FRAME_1_START = 2; + private static final int FRAME_2_START = 76; + private static final int ESS_A1_START = 148; + private static final int ESS_A1_LENGTH = 96; + private static final int ESS_A2_START = 246; + private static final int ESS_A2_LENGTH = 72; + + private List mVoiceFrames; + private BinaryMessage mEssA; + + /** + * Constructs a 2-Voice timeslot + * @param message containing 320 scrambled bits for the timeslot + * @param scramblingSequence to de-scramble the message + * @param timeslot for the message + * @param timestamp of the last transmitted bit + */ + public Voice2Timeslot(CorrectedBinaryMessage message, BinaryMessage scramblingSequence, int timeslot, + long timestamp) + { + super(message, DataUnitID.VOICE_2, scramblingSequence, timeslot, timestamp); + } + + /** + * Voice frames contained in this timeslot + */ + public List getVoiceFrames() + { + if(mVoiceFrames == null) + { + mVoiceFrames = new ArrayList<>(); + mVoiceFrames.add(getMessage().getSubMessage(FRAME_1_START, FRAME_1_START + FRAME_LENGTH)); + mVoiceFrames.add(getMessage().getSubMessage(FRAME_2_START, FRAME_2_START + FRAME_LENGTH)); + return mVoiceFrames; + } + + return mVoiceFrames; + } + + /** + * Encryption Synchronization Signaling (ESS-A) segment + */ + public BinaryMessage getEssA() + { + if(mEssA == null) + { + BinaryMessage segment1 = getMessage().getSubMessage(ESS_A1_START, ESS_A1_START + ESS_A1_LENGTH); + BinaryMessage segment2 = getMessage().getSubMessage(ESS_A2_START, ESS_A2_START + ESS_A2_LENGTH); + mEssA = new BinaryMessage(ESS_A1_LENGTH + ESS_A2_LENGTH); + mEssA.load(0, segment1); + mEssA.load(ESS_A1_LENGTH, segment2); + } + + return mEssA; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/Voice4Timeslot.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/Voice4Timeslot.java new file mode 100644 index 000000000..bd2f88425 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/timeslot/Voice4Timeslot.java @@ -0,0 +1,92 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.module.decode.p25.phase2.timeslot; + +import io.github.dsheirer.bits.BinaryMessage; +import io.github.dsheirer.bits.CorrectedBinaryMessage; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.DataUnitID; + +import java.util.ArrayList; +import java.util.List; + +/** + * Timeslot containing four voice frames and Encryption Sync Signalling (ESS-B) fragment. + */ +public class Voice4Timeslot extends AbstractVoiceTimeslot +{ + private static final int FRAME_LENGTH = 72; + private static final int FRAME_1_START = 2; + private static final int FRAME_2_START = 76; + private static final int FRAME_3_START = 172; + private static final int FRAME_4_START = 246; + private static final int ESS_B_START = 148; + private static final int ESS_B_LENGTH = 24; + + private List mVoiceFrames; + private BinaryMessage mEssB; + + /** + * Constructs a 4-Voice timeslot + * + * @param message containing 320 scrambled bits for the timeslot + * @param scramblingSequence to descramble the message + * @param timeslot of the message + * @param timestamp of the last transmitted bit + */ + public Voice4Timeslot(CorrectedBinaryMessage message, BinaryMessage scramblingSequence, int timeslot, + long timestamp) + { + super(message, DataUnitID.VOICE_4, scramblingSequence, timeslot, timestamp); + } + + /** + * Voice frames contained in this timeslot + */ + public List getVoiceFrames() + { + if(mVoiceFrames == null) + { + mVoiceFrames = new ArrayList<>(); + mVoiceFrames.add(getMessage().getSubMessage(FRAME_1_START, FRAME_1_START + FRAME_LENGTH)); + mVoiceFrames.add(getMessage().getSubMessage(FRAME_2_START, FRAME_2_START + FRAME_LENGTH)); + mVoiceFrames.add(getMessage().getSubMessage(FRAME_3_START, FRAME_3_START + FRAME_LENGTH)); + mVoiceFrames.add(getMessage().getSubMessage(FRAME_4_START, FRAME_4_START + FRAME_LENGTH)); + return mVoiceFrames; + } + + return mVoiceFrames; + } + + /** + * Encryption Synchronization Signaling (ESS-B) segment + */ + public BinaryMessage getEssB() + { + if(mEssB == null) + { + mEssB = getMessage().getSubMessage(ESS_B_START, ESS_B_START + ESS_B_LENGTH); + } + + return mEssB; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/reference/ChannelType.java b/src/main/java/io/github/dsheirer/module/decode/p25/reference/ChannelType.java index 20f1cb379..3997ddf03 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/reference/ChannelType.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/reference/ChannelType.java @@ -20,6 +20,9 @@ package io.github.dsheirer.module.decode.p25.reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public enum ChannelType { TYPE_0(AccessType.FDMA, 12500, 1, Vocoder.HALF_RATE), @@ -28,7 +31,7 @@ public enum ChannelType TYPE_3(AccessType.TDMA, 12500, 2, Vocoder.HALF_RATE), TYPE_4(AccessType.TDMA, 25000, 4, Vocoder.HALF_RATE), TYPE_5(AccessType.TDMA, 12500, 2, Vocoder.HALF_RATE), //HD8PSK simulcast - UNKNOWN(AccessType.UNKNOWN, 0, 0, Vocoder.HALF_RATE); + UNKNOWN(AccessType.UNKNOWN, 0, 1, Vocoder.HALF_RATE); private AccessType mAccessType; private int mBandwidth; @@ -43,6 +46,8 @@ public enum ChannelType mVocoder = vocoder; } + private final static Logger mLog = LoggerFactory.getLogger(ChannelType.class); + public String toString() { StringBuilder sb = new StringBuilder(); @@ -80,6 +85,8 @@ public static ChannelType fromValue(int value) return ChannelType.values()[value]; } + mLog.warn("Unrecognized Channel Type Value [" + value + "]"); + return ChannelType.UNKNOWN; } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/reference/Encryption.java b/src/main/java/io/github/dsheirer/module/decode/p25/reference/Encryption.java index fa5472284..7069f634d 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/reference/Encryption.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/reference/Encryption.java @@ -1,71 +1,101 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + package io.github.dsheirer.module.decode.p25.reference; public enum Encryption { - ACCORDION_1_3( 0x00 ), - BATON_AUTO_EVEN( 0x01 ), - FIREFLY_TYPE1( 0x02 ), - MAYFLY_TYPE1( 0x03 ), - SAVILLE( 0x04 ), - BATON_AUTO_ODD( 0x41 ), - UNENCRYPTED( 0x80 ), - DES_OFB( 0x81 ), - TRIPLE_DES_2_KEY( 0x82 ), - TRIPLE_DES_3_KEY( 0x83 ), - AES_256( 0x84 ), - AES_CBC( 0x85 ), - DES_XL( 0x9F ), /* Motorola Proprietary */ - DVI_XL( 0xA0 ), /* Motorola Proprietary */ - DVP_XL( 0xA1 ), /* Motorola Proprietary */ - ADP( 0xAA ), - UNKNOWN( -1 ); - - private int mValue; - - private Encryption( int value ) - { - mValue = value; - } - - public static Encryption fromValue( int value ) - { - switch( value ) - { - case 0x00: - return ACCORDION_1_3; - case 0x01: - return BATON_AUTO_EVEN; - case 0x02: - return FIREFLY_TYPE1; - case 0x03: - return MAYFLY_TYPE1; - case 0x04: - return SAVILLE; - case 0x41: - return BATON_AUTO_ODD; - case 0x80: - return UNENCRYPTED; - case 0x81: - return DES_OFB; - case 0x82: - return TRIPLE_DES_2_KEY; - case 0x83: - return TRIPLE_DES_3_KEY; - case 0x84: - return AES_256; - case 0x85: - return AES_CBC; - case 0x9F: - return DES_XL; - case 0xA0: - return DVI_XL; - case 0xA1: - return DVP_XL; - case 0xAA: - return ADP; - default: - return UNKNOWN; - } - - } + ACCORDION_3(0x00, "ACCORDIAN 3"), + BATON_AUTO_EVEN(0x01, "BATON AUTO EVEN"), + FIREFLY_TYPE1(0x02, "FIREFLY"), + MAYFLY_TYPE1(0x03, "MAYFLY"), + SAVILLE(0x04, "SAVILLE"), + BATON_AUTO_ODD(0x41, "BATON AUTO ODD"), + UNENCRYPTED(0x80, "UNENCRYPTED"), + DES_OFB(0x81, "DES OFB"), + TRIPLE_DES_2_KEY(0x82, "TRIPLE DES 2"), + TRIPLE_DES_3_KEY(0x83, "TRIPLE DES 3"), + AES_256(0x84, "AES-256"), + AES_CBC(0x85, "AES-CBC"), + DES_XL(0x9F, "DES-XL"), /* Motorola Proprietary */ + DVI_XL(0xA0, "DVI-XL"), /* Motorola Proprietary */ + DVP_XL(0xA1, "DVP-XL"), /* Motorola Proprietary */ + ADP(0xAA, "ADP"), + UNKNOWN(-1, "UNKNOWN"); + + private int mValue; + private String mLabel; + + Encryption(int value, String label) + { + mValue = value; + mLabel = label; + } + + @Override + public String toString() + { + return mLabel; + } + + public static Encryption fromValue(int value) + { + switch(value) + { + case 0x00: + return ACCORDION_3; + case 0x01: + return BATON_AUTO_EVEN; + case 0x02: + return FIREFLY_TYPE1; + case 0x03: + return MAYFLY_TYPE1; + case 0x04: + return SAVILLE; + case 0x41: + return BATON_AUTO_ODD; + case 0x80: + return UNENCRYPTED; + case 0x81: + return DES_OFB; + case 0x82: + return TRIPLE_DES_2_KEY; + case 0x83: + return TRIPLE_DES_3_KEY; + case 0x84: + return AES_256; + case 0x85: + return AES_CBC; + case 0x9F: + return DES_XL; + case 0xA0: + return DVI_XL; + case 0xA1: + return DVP_XL; + case 0xAA: + return ADP; + default: + return UNKNOWN; + } + + } } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/reference/SystemServiceClass.java b/src/main/java/io/github/dsheirer/module/decode/p25/reference/SystemServiceClass.java new file mode 100644 index 000000000..7e4622027 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/p25/reference/SystemServiceClass.java @@ -0,0 +1,97 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.module.decode.p25.reference; + +import java.util.ArrayList; +import java.util.List; + +public class SystemServiceClass +{ + private static final int NO_SERVICES = 0x00; + + private static final int COMPOSITE_CONTROL_CHANNEL = 0x01; + private static final int NO_SERVICE_REQUESTS = 0x02; + private static final int BACKUP_CONTROL_CHANNEL = 0x04; + private static final int DATA_SERVICE = 0x10; + private static final int VOICE_SERVICE = 0x20; + private static final int REGISTRATION_SERVICE = 0x40; + private static final int AUTHENTICATION_SERVICE = 0x80; + + private int mSystemServiceClass; + + public SystemServiceClass(int systemServiceClass) + { + mSystemServiceClass = systemServiceClass; + } + + public List getServices() + { + List services = new ArrayList<>(); + + if(hasFlag(DATA_SERVICE)) + { + services.add("DATA"); + } + if(hasFlag(VOICE_SERVICE)) + { + services.add("VOICE"); + } + if(hasFlag(REGISTRATION_SERVICE)) + { + services.add("REGISTRATION"); + } + if(hasFlag(AUTHENTICATION_SERVICE)) + { + services.add("AUTHENTICATION"); + } + if(hasFlag(COMPOSITE_CONTROL_CHANNEL)) + { + services.add("COMPOSITE CONTROL CHANNEL"); + } + if(hasFlag(NO_SERVICE_REQUESTS)) + { + services.add("NO SERVICE REQUESTS"); + } + if(hasFlag(BACKUP_CONTROL_CHANNEL)) + { + services.add("BACKUP CONTROL CHANNEL"); + } + + return services; + } + + private boolean hasFlag(int flag) + { + return (mSystemServiceClass & flag) == flag; + } + + @Override + public String toString() + { + return getServices().toString(); + } + + public static SystemServiceClass create(int systemServiceClass) + { + return new SystemServiceClass(systemServiceClass); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/reference/Vendor.java b/src/main/java/io/github/dsheirer/module/decode/p25/reference/Vendor.java index 4d2958934..5c424fcc7 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/reference/Vendor.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/reference/Vendor.java @@ -166,7 +166,7 @@ public enum Vendor V161( "VENDORA1", "V_A1", 161), V162( "VENDORA2", "V_A2", 162), V163( "VENDORA3", "V_A3", 163), - MACOM( "M/A-COM ", "M/A-COM", 164), + HARRIS( "HARRIS", "HARRIS", 164), V165( "VENDORA5", "V_A5", 165), V166( "VENDORA6", "V_A6", 166), V167( "VENDORA7", "V_A7", 167), diff --git a/src/main/java/io/github/dsheirer/module/decode/passport/PassportDecoderState.java b/src/main/java/io/github/dsheirer/module/decode/passport/PassportDecoderState.java index 7a47bad84..6f9d55cc9 100644 --- a/src/main/java/io/github/dsheirer/module/decode/passport/PassportDecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/passport/PassportDecoderState.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.passport; @@ -325,6 +327,7 @@ public String getActivitySummary() public void reset() { + super.reset(); getIdentifierCollection().remove(IdentifierClass.USER); mTalkgroupsFirstHeard.clear(); mTalkgroups.clear(); diff --git a/src/main/java/io/github/dsheirer/module/decode/tait/Tait1200DecoderState.java b/src/main/java/io/github/dsheirer/module/decode/tait/Tait1200DecoderState.java index c2ce76a26..a53106833 100644 --- a/src/main/java/io/github/dsheirer/module/decode/tait/Tait1200DecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/tait/Tait1200DecoderState.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.decode.tait; @@ -51,6 +53,7 @@ public DecoderType getDecoderType() @Override public void reset() { + super.reset(); mIdents.clear(); resetState(); } diff --git a/src/main/java/io/github/dsheirer/module/log/DecodeEventLogger.java b/src/main/java/io/github/dsheirer/module/log/DecodeEventLogger.java index 68d75393d..a04a48896 100644 --- a/src/main/java/io/github/dsheirer/module/log/DecodeEventLogger.java +++ b/src/main/java/io/github/dsheirer/module/log/DecodeEventLogger.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.module.log; @@ -77,7 +79,7 @@ public void reset() public static String getCSVHeader() { - return "TIMESTAMP,DURATION_MS,PROTOCOL,EVENT,FROM,TO,CHANNEL_NUMBER,FREQUENCY,DETAILS"; + return "TIMESTAMP,DURATION_MS,PROTOCOL,EVENT,FROM,TO,CHANNEL_NUMBER,FREQUENCY,TIMESLOT,DETAILS"; } private String toCSV(IDecodeEvent event) @@ -127,6 +129,15 @@ private String toCSV(IDecodeEvent event) sb.append(",\"\""); } + if(event.hasTimeslot()) + { + sb.append(",\"TS:").append(event.getTimeslot()); + } + else + { + sb.append(",\"\""); + } + String details = event.getDetails(); sb.append(",\"").append(details != null ? details : "").append("\""); diff --git a/src/main/java/io/github/dsheirer/preference/decoder/JmbeLibraryPreference.java b/src/main/java/io/github/dsheirer/preference/decoder/JmbeLibraryPreference.java index d34b76ac6..49108f76e 100644 --- a/src/main/java/io/github/dsheirer/preference/decoder/JmbeLibraryPreference.java +++ b/src/main/java/io/github/dsheirer/preference/decoder/JmbeLibraryPreference.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.preference.decoder; @@ -39,7 +41,7 @@ public class JmbeLibraryPreference extends Preference private final static Logger mLog = LoggerFactory.getLogger(JmbeLibraryPreference.class); private Preferences mPreferences = Preferences.userNodeForPackage(JmbeLibraryPreference.class); - private static final String PREFERENCE_KEY_PATH_JMBE_LIBRARY = "path.jmbe.library"; + private static final String PREFERENCE_KEY_PATH_JMBE_LIBRARY = "path.jmbe.library.1.0.0"; private Path mPathJmbeLibrary; /** diff --git a/src/main/java/io/github/dsheirer/protocol/Protocol.java b/src/main/java/io/github/dsheirer/protocol/Protocol.java index e6d8d30af..a245dd3a8 100644 --- a/src/main/java/io/github/dsheirer/protocol/Protocol.java +++ b/src/main/java/io/github/dsheirer/protocol/Protocol.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.protocol; @@ -27,6 +29,7 @@ public enum Protocol { APCO25("APCO-25", "APCO25PHASE1", 9600), + APCO25_PHASE2("APCO-25 P2", "APCO25PHASE2", 12000), FLEETSYNC("Fleetsync", "FLEETSYNC", 1200), IPV4("IPV4", "IPV4", 0), LOJACK("LoJack", "LOJACK", 1200), diff --git a/src/main/java/io/github/dsheirer/record/RecordConfigurationEditor.java b/src/main/java/io/github/dsheirer/record/RecordConfigurationEditor.java index 2394682ad..1ab3a7378 100644 --- a/src/main/java/io/github/dsheirer/record/RecordConfigurationEditor.java +++ b/src/main/java/io/github/dsheirer/record/RecordConfigurationEditor.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.record; import io.github.dsheirer.controller.channel.Channel; @@ -33,6 +39,8 @@ public class RecordConfigurationEditor extends Editor private JCheckBox mTrafficBasebandRecorder; private JCheckBox mBitstreamRecorder; private JCheckBox mTrafficBitstreamRecorder; + private JCheckBox mMBERecorder; + private JCheckBox mTrafficMBERecorder; public RecordConfigurationEditor() { @@ -43,7 +51,7 @@ private void init() { setLayout(new MigLayout("fill,wrap 2", "", "[][][][grow]")); - mBasebandRecorder = new JCheckBox("Baseband I/Q"); + mBasebandRecorder = new JCheckBox(RecorderType.BASEBAND.getDisplayString()); mBasebandRecorder.setEnabled(false); mBasebandRecorder.addActionListener(new ActionListener() { @@ -55,7 +63,7 @@ public void actionPerformed(ActionEvent e) }); add(mBasebandRecorder); - mTrafficBasebandRecorder = new JCheckBox("Traffic Channel Baseband I/Q"); + mTrafficBasebandRecorder = new JCheckBox(RecorderType.TRAFFIC_BASEBAND.getDisplayString()); mTrafficBasebandRecorder.setEnabled(false); mTrafficBasebandRecorder.addActionListener(new ActionListener() { @@ -67,7 +75,7 @@ public void actionPerformed(ActionEvent e) }); add(mTrafficBasebandRecorder); - mBitstreamRecorder = new JCheckBox("Demodulated Bitstream"); + mBitstreamRecorder = new JCheckBox(RecorderType.DEMODULATED_BIT_STREAM.getDisplayString()); mBitstreamRecorder.setEnabled(false); mBitstreamRecorder.addActionListener(new ActionListener() { @@ -79,7 +87,7 @@ public void actionPerformed(ActionEvent e) }); add(mBitstreamRecorder); - mTrafficBitstreamRecorder = new JCheckBox("Traffic Channel Bitstream"); + mTrafficBitstreamRecorder = new JCheckBox(RecorderType.TRAFFIC_DEMODULATED_BIT_STREAM.getDisplayString()); mTrafficBitstreamRecorder.setEnabled(false); mTrafficBitstreamRecorder.addActionListener(new ActionListener() { @@ -90,6 +98,30 @@ public void actionPerformed(ActionEvent e) } }); add(mTrafficBitstreamRecorder); + + mMBERecorder = new JCheckBox(RecorderType.MBE_CALL_SEQUENCE.getDisplayString()); + mMBERecorder.setEnabled(false); + mMBERecorder.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + setModified(true); + } + }); + add(mMBERecorder); + + mTrafficMBERecorder = new JCheckBox(RecorderType.TRAFFIC_MBE_CALL_SEQUENCE.getDisplayString()); + mTrafficMBERecorder.setEnabled(false); + mTrafficMBERecorder.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + setModified(true); + } + }); + add(mTrafficMBERecorder); } private void setControlsEnabled(boolean enabled) @@ -113,6 +145,16 @@ private void setControlsEnabled(boolean enabled) { mTrafficBitstreamRecorder.setEnabled(enabled); } + + if(mMBERecorder.isEnabled() != enabled) + { + mMBERecorder.setEnabled(enabled); + } + + if(mTrafficMBERecorder.isEnabled() != enabled) + { + mTrafficMBERecorder.setEnabled(enabled); + } } @Override @@ -134,15 +176,29 @@ public void save() config.addRecorder(RecorderType.TRAFFIC_BASEBAND); } - if(mBitstreamRecorder.isSelected()) + boolean providesBitstream = getItem().getDecodeConfiguration().getDecoderType().providesBitstream(); + + if(providesBitstream && mBitstreamRecorder.isSelected()) { config.addRecorder(RecorderType.DEMODULATED_BIT_STREAM); } - if(mTrafficBitstreamRecorder.isSelected()) + if(providesBitstream && mTrafficBitstreamRecorder.isSelected()) { config.addRecorder(RecorderType.TRAFFIC_DEMODULATED_BIT_STREAM); } + + boolean providesMBE = getItem().getDecodeConfiguration().getDecoderType().providesMBEAudioFrames(); + + if(providesMBE && mMBERecorder.isSelected()) + { + config.addRecorder(RecorderType.MBE_CALL_SEQUENCE); + } + + if(providesMBE && mTrafficMBERecorder.isSelected()) + { + config.addRecorder(RecorderType.TRAFFIC_MBE_CALL_SEQUENCE); + } } setModified(false); @@ -160,12 +216,46 @@ public void setItem(Channel channel) List recorders = getItem().getRecordConfiguration().getRecorders(); mBasebandRecorder.setSelected(recorders.contains(RecorderType.BASEBAND)); mTrafficBasebandRecorder.setSelected(recorders.contains(RecorderType.TRAFFIC_BASEBAND)); - mBitstreamRecorder.setSelected(recorders.contains(RecorderType.DEMODULATED_BIT_STREAM)); - mTrafficBitstreamRecorder.setSelected(recorders.contains(RecorderType.TRAFFIC_DEMODULATED_BIT_STREAM)); + + boolean providesBitstream = channel.getDecodeConfiguration().getDecoderType().providesBitstream(); + + if(providesBitstream) + { + mBitstreamRecorder.setSelected(recorders.contains(RecorderType.DEMODULATED_BIT_STREAM)); + mTrafficBitstreamRecorder.setSelected(recorders.contains(RecorderType.TRAFFIC_DEMODULATED_BIT_STREAM)); + } + else + { + mBitstreamRecorder.setSelected(false); + mBitstreamRecorder.setEnabled(false); + mTrafficBitstreamRecorder.setSelected(false); + mTrafficBitstreamRecorder.setEnabled(false); + } + + boolean providesMBEFrames = channel.getDecodeConfiguration().getDecoderType().providesMBEAudioFrames(); + + if(providesMBEFrames) + { + mMBERecorder.setSelected(recorders.contains(RecorderType.MBE_CALL_SEQUENCE)); + mTrafficMBERecorder.setSelected(recorders.contains(RecorderType.TRAFFIC_MBE_CALL_SEQUENCE)); + } + else + { + mMBERecorder.setSelected(false); + mMBERecorder.setEnabled(false); + mTrafficMBERecorder.setSelected(false); + mTrafficMBERecorder.setEnabled(false); + } } else { setControlsEnabled(false); + mBasebandRecorder.setSelected(false); + mBitstreamRecorder.setSelected(false); + mMBERecorder.setSelected(false); + mTrafficMBERecorder.setSelected(false); + mTrafficBitstreamRecorder.setSelected(false); + mTrafficBasebandRecorder.setSelected(false); } } } diff --git a/src/main/java/io/github/dsheirer/record/RecorderFactory.java b/src/main/java/io/github/dsheirer/record/RecorderFactory.java new file mode 100644 index 000000000..32a4fe6b9 --- /dev/null +++ b/src/main/java/io/github/dsheirer/record/RecorderFactory.java @@ -0,0 +1,139 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.record; + +import io.github.dsheirer.controller.channel.Channel; +import io.github.dsheirer.module.Module; +import io.github.dsheirer.module.decode.p25.audio.P25P1CallSequenceRecorder; +import io.github.dsheirer.module.decode.p25.audio.P25P2CallSequenceRecorder; +import io.github.dsheirer.preference.UserPreferences; +import io.github.dsheirer.record.binary.BinaryRecorder; +import io.github.dsheirer.source.config.SourceConfigTuner; +import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency; + +import java.util.ArrayList; +import java.util.List; + +public class RecorderFactory +{ + /** + * Creates recorder modules based on the channel configuration details + * @param recorderManager + * @param userPreferences + * @param channel + * @return + */ + public static List getRecorders(RecorderManager recorderManager, UserPreferences userPreferences, Channel channel) + { + List recorderModules = new ArrayList<>(); + + for(RecorderType recorderType: channel.getRecordConfiguration().getRecorders()) + { + switch(recorderType) + { + case BASEBAND: + if(channel.isStandardChannel()) + { + recorderModules.add(recorderManager.getBasebandRecorder(channel.toString())); + } + break; + case DEMODULATED_BIT_STREAM: + if(channel.isStandardChannel() && channel.getDecodeConfiguration().getDecoderType().providesBitstream()) + { + recorderModules.add(new BinaryRecorder(recorderManager.getRecordingBasePath(), + channel.toString(), channel.getDecodeConfiguration().getDecoderType().getProtocol())); + } + break; + case TRAFFIC_BASEBAND: + if(channel.isTrafficChannel()) + { + recorderModules.add(recorderManager.getBasebandRecorder(channel.toString())); + } + break; + case TRAFFIC_DEMODULATED_BIT_STREAM: + if(channel.isTrafficChannel() && channel.getDecodeConfiguration().getDecoderType().providesBitstream()) + { + recorderModules.add(new BinaryRecorder(recorderManager.getRecordingBasePath(), + channel.toString(), channel.getDecodeConfiguration().getDecoderType().getProtocol())); + } + break; + case MBE_CALL_SEQUENCE: + if(channel.isStandardChannel() && channel.getSourceConfiguration() instanceof SourceConfigTuner) + { + long frequency = 0; + + if(channel.getSourceConfiguration() instanceof SourceConfigTuner) + { + frequency = ((SourceConfigTuner)channel.getSourceConfiguration()).getFrequency(); + } + else if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency) + { + frequency = ((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).getFrequencies().get(0); + } + + switch(channel.getDecodeConfiguration().getDecoderType()) + { + case P25_PHASE1: + recorderModules.add(new P25P1CallSequenceRecorder(userPreferences, frequency, + channel.getSystem(), channel.getSite())); + break; + case P25_PHASE2: + recorderModules.add(new P25P2CallSequenceRecorder(userPreferences, frequency, + channel.getSystem(), channel.getSite())); + break; + } + } + break; + case TRAFFIC_MBE_CALL_SEQUENCE: + if(channel.isTrafficChannel() && channel.getSourceConfiguration() instanceof SourceConfigTuner) + { + long frequency = 0; + + if(channel.getSourceConfiguration() instanceof SourceConfigTuner) + { + frequency = ((SourceConfigTuner)channel.getSourceConfiguration()).getFrequency(); + } + else if(channel.getSourceConfiguration() instanceof SourceConfigTunerMultipleFrequency) + { + frequency = ((SourceConfigTunerMultipleFrequency)channel.getSourceConfiguration()).getFrequencies().get(0); + } + + switch(channel.getDecodeConfiguration().getDecoderType()) + { + case P25_PHASE1: + recorderModules.add(new P25P1CallSequenceRecorder(userPreferences, frequency, + channel.getSystem(), channel.getSite())); + break; + case P25_PHASE2: + recorderModules.add(new P25P2CallSequenceRecorder(userPreferences, frequency, + channel.getSystem(), channel.getSite())); + break; + } + } + break; + } + } + + return recorderModules; + } +} diff --git a/src/main/java/io/github/dsheirer/record/RecorderManager.java b/src/main/java/io/github/dsheirer/record/RecorderManager.java index 4a398a094..9ccfb98e1 100644 --- a/src/main/java/io/github/dsheirer/record/RecorderManager.java +++ b/src/main/java/io/github/dsheirer/record/RecorderManager.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.record; @@ -275,14 +277,16 @@ private Path getFinalFileName(IdentifierCollection identifierCollection) if(to != null) { - sb.append("_TO_").append(((IntegerIdentifier)to).getValue()); + String toValue = ((IntegerIdentifier)to).getValue().toString().replace(":", ""); + sb.append("_TO_").append(toValue); } Identifier from = identifierCollection.getIdentifier(IdentifierClass.USER, Form.TALKGROUP, Role.FROM); if(from != null) { - sb.append("_FROM_").append(((IntegerIdentifier)from).getValue()); + String fromValue = ((IntegerIdentifier)from).getValue().toString().replace(":", ""); + sb.append("_FROM_").append(fromValue); } } else diff --git a/src/main/java/io/github/dsheirer/record/RecorderType.java b/src/main/java/io/github/dsheirer/record/RecorderType.java index 2bfa12f3a..9627f6f75 100644 --- a/src/main/java/io/github/dsheirer/record/RecorderType.java +++ b/src/main/java/io/github/dsheirer/record/RecorderType.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.record; import java.util.EnumSet; @@ -45,7 +51,17 @@ public enum RecorderType /** * Traffic channel demodulated bit stream at the baud rate of the decoder */ - TRAFFIC_DEMODULATED_BIT_STREAM("Traffic Channel Demodulated Bitstream (.bits)"); + TRAFFIC_DEMODULATED_BIT_STREAM("Traffic Channel Demodulated Bitstream (.bits)"), + + /** + * MBE Audio Codec frames + */ + MBE_CALL_SEQUENCE("MBE Audio CODEC Frames (.mbe)"), + + /** + * Traffic channel MBE Audio Codec frames + */ + TRAFFIC_MBE_CALL_SEQUENCE("Traffic Channel MBE Audio CODEC Frames (.mbe)"); private String mDisplayString; diff --git a/src/main/java/io/github/dsheirer/sample/complex/Complex.java b/src/main/java/io/github/dsheirer/sample/complex/Complex.java index f61f45a52..06234564e 100644 --- a/src/main/java/io/github/dsheirer/sample/complex/Complex.java +++ b/src/main/java/io/github/dsheirer/sample/complex/Complex.java @@ -1,20 +1,24 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014 Dennis Sheirer +/* * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - ******************************************************************************/ + */ package io.github.dsheirer.sample.complex; import org.slf4j.Logger; @@ -396,9 +400,22 @@ public float angle() return (float)Math.atan2(y(), x()); } - public float angleDegrees() + /** + * Angle in degrees + * @return angle value (-180.0 to 180.0) relative to engineering 0 degrees (ie due East) + */ + public double angleDegrees() { - return (float)Math.toDegrees(angle()); + return Math.toDegrees(Math.atan2(y(), x())); + } + + /** + * Angle in polar degrees relative to true North + */ + public double polarAngleDegrees() + { + double angle = Math.toDegrees(Math.atan2(y(), x())); + return (450.0 - angle) % 360.0; } /** diff --git a/src/main/java/io/github/dsheirer/source/SourceEvent.java b/src/main/java/io/github/dsheirer/source/SourceEvent.java index fe4892373..cb200e9d1 100644 --- a/src/main/java/io/github/dsheirer/source/SourceEvent.java +++ b/src/main/java/io/github/dsheirer/source/SourceEvent.java @@ -36,6 +36,7 @@ public enum Event NOTIFICATION_FREQUENCY_ROTATION_FAILURE, NOTIFICATION_MEASURED_FREQUENCY_ERROR, NOTIFICATION_MEASURED_FREQUENCY_ERROR_SYNC_LOCKED, + NOTIFICATION_RECORDING_FILE_LOADED, NOTIFICATION_SAMPLE_RATE_CHANGE, NOTIFICATION_STOP_SAMPLE_STREAM, @@ -276,6 +277,14 @@ public static SourceEvent channelSampleRateChange(double sampleRate) return new SourceEvent(Event.NOTIFICATION_CHANNEL_SAMPLE_RATE_CHANGE, sampleRate); } + /** + * Notification that a baseband recording file has been loaded + */ + public static SourceEvent recordingFileLoaded() + { + return new SourceEvent(Event.NOTIFICATION_RECORDING_FILE_LOADED); + } + /** * Creates a new channel count change event * diff --git a/src/main/java/io/github/dsheirer/source/tuner/Tuner.java b/src/main/java/io/github/dsheirer/source/tuner/Tuner.java index f94f11dcb..745234ab4 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/Tuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/Tuner.java @@ -46,39 +46,52 @@ public abstract class Tuner implements ISourceEventProcessor private TunerFrequencyErrorMonitor mTunerFrequencyErrorMonitor; private String mName; + public Tuner(String name, TunerController tunerController) + { + mName = name; + mTunerController = tunerController; + //Register to receive frequency and sample rate change notifications + mTunerController.addListener(this::process); + + mTunerFrequencyErrorMonitor = new TunerFrequencyErrorMonitor(this); + mTunerFrequencyErrorMonitor.start(); + } + /** * Abstract tuner class. * @param name of the tuner * @param tunerController for the tuner + * @param userPreferences to discover preferred channelizer type */ public Tuner(String name, TunerController tunerController, UserPreferences userPreferences) { - mName = name; - mTunerController = tunerController; - //Register to receive frequency and sample rate change notifications - mTunerController.addListener(this::process); + this(name, tunerController); ChannelizerType channelizerType = userPreferences.getTunerPreference().getChannelizerType(); - if(channelizerType == ChannelizerType.POLYPHASE) { - mChannelSourceManager = new PolyphaseChannelSourceManager(mTunerController); + setChannelSourceManager(new PolyphaseChannelSourceManager(mTunerController)); } else if(channelizerType == ChannelizerType.HETERODYNE) { - mChannelSourceManager = new HeterodyneChannelSourceManager(mTunerController); + setChannelSourceManager(new HeterodyneChannelSourceManager(mTunerController)); } else { throw new IllegalArgumentException("Unrecognized channelizer type: " + channelizerType); } + } + /** + * Sets the channel source manager + * @param manager to use + */ + protected void setChannelSourceManager(ChannelSourceManager manager) + { + mChannelSourceManager = manager; //Register to receive channel count change notifications mChannelSourceManager.addSourceEventListener(this::process); - - mTunerFrequencyErrorMonitor = new TunerFrequencyErrorMonitor(this); - mTunerFrequencyErrorMonitor.start(); } @Override @@ -105,6 +118,9 @@ public void process(SourceEvent event) case NOTIFICATION_MEASURED_FREQUENCY_ERROR_SYNC_LOCKED: mTunerFrequencyErrorMonitor.receive(event); break; + case NOTIFICATION_RECORDING_FILE_LOADED: + //ignore + break; default: mLog.debug("Unrecognized Source Event: " + event.toString()); break; diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerClass.java b/src/main/java/io/github/dsheirer/source/tuner/TunerClass.java index 2086d137c..9278ac5fb 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerClass.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerClass.java @@ -1,20 +1,24 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014 Dennis Sheirer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - ******************************************************************************/ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ package io.github.dsheirer.source.tuner; import javax.usb.UsbDeviceDescriptor; @@ -53,6 +57,7 @@ public enum TunerClass TWINTECH_UT40( TunerType.FITIPOWER_FC0013, "1B80", "D3A4", "Twintech", "UT-40" ), ZAAPA_ZTMINDVBZP( TunerType.FITIPOWER_FC0012, "1B80", "D398", "Zaapa", "ZT-MINDVBZP" ), TEST_TUNER(TunerType.TEST, "0", "0", "ABC Tuners Inc.", "Model XYZ"), + RECORDING_TUNER(TunerType.RECORDING, "0", "0", "Recording Tuner", "Recording"), UNKNOWN( TunerType.UNKNOWN, "0", "0", "Unknown Manufacturer", "Unknown Device" ); private TunerType mTunerType; diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerController.java b/src/main/java/io/github/dsheirer/source/tuner/TunerController.java index 92e5e053e..cdc0713a4 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerController.java @@ -1,22 +1,28 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014-2017 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - ******************************************************************************/ + */ package io.github.dsheirer.source.tuner; +import io.github.dsheirer.record.RecorderManager; +import io.github.dsheirer.record.wave.ComplexBufferWaveRecorder; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.buffer.IReusableComplexBufferProvider; import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster; @@ -45,6 +51,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor, private double mUsableBandwidthPercentage; private Listener mSourceEventListener; private int mMeasuredFrequencyError; + private ComplexBufferWaveRecorder mRecorder; /** * Abstract tuner controller class. The tuner controller manages frequency bandwidth and currently tuned channels @@ -445,4 +452,40 @@ public boolean isTunedFor(SortedSet tunerChannels) return true; } + + /** + * Records the complex I/Q buffers produced by the tuner + * @param recorderManager to obtain a baseband recorder + */ + public void startRecorder(RecorderManager recorderManager) + { + if(!isRecording()) + { + mRecorder = recorderManager.getBasebandRecorder("TUNER_" + getFrequency()); + mRecorder.setSampleRate((float)getSampleRate()); + mRecorder.start(); + addBufferListener(mRecorder); + } + } + + /** + * Stops the recording of complex I/Q buffers + */ + public void stopRecorder() + { + if(isRecording()) + { + removeBufferListener(mRecorder); + mRecorder.stop(); + mRecorder = null; + } + } + + /** + * Indicates if this tuner controller is currently reocording the complex I/Q sample buffers produced by this tuner + */ + public boolean isRecording() + { + return mRecorder != null; + } } \ No newline at end of file diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/TunerEditor.java index e72f7d114..354983a29 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerEditor.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.source.tuner; @@ -20,6 +26,7 @@ import io.github.dsheirer.gui.control.JFrequencyControl; import io.github.dsheirer.gui.editor.Editor; import io.github.dsheirer.gui.editor.EmptyEditor; +import io.github.dsheirer.record.RecorderManager; import io.github.dsheirer.source.tuner.configuration.TunerConfiguration; import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEditor; import io.github.dsheirer.source.tuner.configuration.TunerConfigurationFactory; @@ -34,6 +41,7 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; +import javax.swing.JToggleButton; import javax.swing.RowFilter; import javax.swing.ScrollPaneConstants; import javax.swing.event.ListSelectionEvent; @@ -53,6 +61,7 @@ public class TunerEditor extends Editor private JTable mTunerConfigurationTable; private TableRowSorter mRowSorter; private JFrequencyControl mFrequencyControl = new JFrequencyControl(); + private JToggleButton mRecordButton; private JLabel mSelectedTunerType = new JLabel("No Tuner Selected"); private JButton mNewConfigurationButton = new JButton("New"); private JButton mDeleteConfigurationButton = new JButton("Delete"); @@ -60,10 +69,12 @@ public class TunerEditor extends Editor private JScrollPane mEditorScroller; private Editor mEditor = new EmptyEditor<>("a tuner"); private JideSplitPane mEditorSplitPane = new JideSplitPane(); + private RecorderManager mRecorderManager; - public TunerEditor(TunerConfigurationModel tunerConfigurationModel) + public TunerEditor(TunerConfigurationModel tunerConfigurationModel, RecorderManager recorderManager) { mTunerConfigurationModel = tunerConfigurationModel; + mRecorderManager = recorderManager; init(); } @@ -88,12 +99,38 @@ public void init() setLayout(new MigLayout("insets 0 0 0 0", "[grow,fill]", "[grow,fill]")); JPanel listPanel = new JPanel(); - listPanel.setLayout(new MigLayout("fill,wrap 3", "[grow,fill]", "[][][][grow,fill][]")); + listPanel.setLayout(new MigLayout("fill,wrap 3", "[grow,fill][grow,fill][grow,fill]", "[][][][grow," + + "fill][]")); listPanel.add(mSelectedTunerType, "span"); mFrequencyControl.setEnabled(false); - listPanel.add(mFrequencyControl, "span"); + listPanel.add(mFrequencyControl, "span 2"); + + mRecordButton = new JToggleButton("Record"); + mRecordButton.setEnabled(false); + mRecordButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + if(mRecordButton.isSelected()) + { + if(hasItem()) + { + getItem().getTunerController().startRecorder(mRecorderManager); + } + } + else + { + if(hasItem()) + { + getItem().getTunerController().stopRecorder(); + } + } + } + }); + listPanel.add(mRecordButton, "wrap"); mRowSorter = new TableRowSorter<>(mTunerConfigurationModel); mTunerConfigurationTable = new JTable(mTunerConfigurationModel); @@ -274,6 +311,9 @@ public void setItem(Tuner tuner) //Set the displayed frequency without adjusting the tuner's frequency mFrequencyControl.setFrequency(tuner.getTunerController().getFrequency(), false); + + mRecordButton.setEnabled(true); + mRecordButton.setSelected(getItem().getTunerController().isRecording()); } else { @@ -283,6 +323,8 @@ public void setItem(Tuner tuner) mNewConfigurationButton.setEnabled(false); mRowSorter.setRowFilter(null); mEditor = new EmptyEditor(); + mRecordButton.setEnabled(false); + mRecordButton.setSelected(false); } //Swap out the editor diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerModel.java b/src/main/java/io/github/dsheirer/source/tuner/TunerModel.java index 948c45c46..e970a6510 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerModel.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerModel.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.source.tuner; @@ -29,6 +31,7 @@ import io.github.dsheirer.source.tuner.channel.TunerChannelSource; import io.github.dsheirer.source.tuner.configuration.TunerConfiguration; import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel; +import io.github.dsheirer.source.tuner.recording.RecordingTuner; import io.github.dsheirer.spectrum.SpectralDisplayPanel; import io.github.dsheirer.util.ThreadPool; import org.slf4j.Logger; @@ -56,6 +59,8 @@ public class TunerModel extends AbstractTableModel implements Listener listener) { mTunerEventListeners.add(listener); diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerType.java b/src/main/java/io/github/dsheirer/source/tuner/TunerType.java index 6b18969d2..43a4631e2 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerType.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerType.java @@ -1,20 +1,24 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014 Dennis Sheirer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - ******************************************************************************/ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ package io.github.dsheirer.source.tuner; public enum TunerType @@ -33,6 +37,7 @@ public enum TunerType RAFAELMICRO_R828D( "R828D" ), RTL2832_VARIOUS( "Generic" ), TEST("Test"), + RECORDING("Recording"), UNKNOWN( "Unknown" ); private String mLabel; diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerViewPanel.java b/src/main/java/io/github/dsheirer/source/tuner/TunerViewPanel.java index 359509650..f4b142089 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerViewPanel.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerViewPanel.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.source.tuner; @@ -23,12 +25,15 @@ import com.jidesoft.swing.JideSplitPane; import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor; +import io.github.dsheirer.record.RecorderManager; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.source.tuner.TunerEvent.Event; +import io.github.dsheirer.source.tuner.recording.RecordingTuner; import net.miginfocom.swing.MigLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -44,6 +49,8 @@ import java.awt.Color; import java.awt.Component; import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; @@ -63,10 +70,10 @@ public class TunerViewPanel extends JPanel private TunerEditor mTunerEditor; private UserPreferences mUserPreferences; - public TunerViewPanel(TunerModel tunerModel, UserPreferences userPreferences) + public TunerViewPanel(TunerModel tunerModel, UserPreferences userPreferences, RecorderManager recorderManager) { mTunerModel = tunerModel; - mTunerEditor = new TunerEditor(mTunerModel.getTunerConfigurationModel()); + mTunerEditor = new TunerEditor(mTunerModel.getTunerConfigurationModel(), recorderManager); mUserPreferences = userPreferences; init(); @@ -158,15 +165,36 @@ public void mouseClicked(MouseEvent e) mTunerTable.getColumnModel().getColumn(TunerModel.SPECTRAL_DISPLAY_NEW).setCellRenderer(renderer); mColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mTunerTable, TABLE_PREFERENCE_KEY); - JScrollPane listScroller = new JScrollPane(mTunerTable); - listScroller.setPreferredSize(new Dimension(400, 20)); + JScrollPane tunerTableScroller = new JScrollPane(mTunerTable); + tunerTableScroller.setPreferredSize(new Dimension(400, 20)); + + JPanel tunerTablePanel = new JPanel(); + tunerTablePanel.setLayout(new MigLayout("insets 0 0 0 0", "[fill,grow][]", "[fill,grow][]")); + tunerTablePanel.add(tunerTableScroller, "span"); + + tunerTablePanel.add(new JLabel("")); //Empty spacer + JButton addRecordingTunerButton = new JButton("Add Recording Tuner"); + addRecordingTunerButton.setEnabled(mTunerModel.canAddRecordingTuner()); + addRecordingTunerButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + RecordingTuner recordingTuner = new RecordingTuner(mUserPreferences); + mTunerModel.addTuner(recordingTuner); + addRecordingTunerButton.setEnabled(mTunerModel.canAddRecordingTuner()); + } + }); + tunerTablePanel.add(addRecordingTunerButton); + + tunerTablePanel.add(addRecordingTunerButton); JScrollPane editorScroller = new JScrollPane(mTunerEditor); editorScroller.setPreferredSize(new Dimension(400, 80)); mSplitPane = new JideSplitPane(); mSplitPane.setOrientation(JideSplitPane.VERTICAL_SPLIT); - mSplitPane.add(listScroller); + mSplitPane.add(tunerTablePanel); mSplitPane.add(editorScroller); add(mSplitPane); diff --git a/src/main/java/io/github/dsheirer/source/tuner/channel/PassThroughChannelSource.java b/src/main/java/io/github/dsheirer/source/tuner/channel/PassThroughChannelSource.java new file mode 100644 index 000000000..ae1c0898a --- /dev/null +++ b/src/main/java/io/github/dsheirer/source/tuner/channel/PassThroughChannelSource.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * sdr-trunk + * 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 + * + ******************************************************************************/ + +package io.github.dsheirer.source.tuner.channel; + +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.OverflowableReusableBufferTransferQueue; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.source.ISourceEventListener; +import io.github.dsheirer.source.SourceEvent; +import io.github.dsheirer.source.tuner.TunerController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * Pass-through channel source that simply passes complex sample buffers from the tuner controller + * directly to the registered listener + */ +public class PassThroughChannelSource extends TunerChannelSource implements ISourceEventListener, + Listener +{ + private final static Logger mLog = LoggerFactory.getLogger(PassThroughChannelSource.class); + private TunerController mTunerController; + private OverflowableReusableBufferTransferQueue mBufferQueue = + new OverflowableReusableBufferTransferQueue<>(500, 100); + private List mBuffersToProcess = new ArrayList<>(); + private Listener mComplexBufferListener; + + /** + * Constructs an instance + * + * @param listener to receive source events + * @param tunerController that provides current sample rate + * @param tunerChannel requested for this channel + */ + public PassThroughChannelSource(Listener listener, TunerController tunerController, + TunerChannel tunerChannel) + { + super(listener, tunerChannel); + mTunerController = tunerController; + } + + @Override + public void setFrequency(long frequency) + { + mLog.debug("Request to set frequency: " + frequency); + } + + @Override + protected void setSampleRate(double sampleRate) + { + mLog.debug("Request to set sample rate: " + sampleRate); + } + + @Override + protected void setChannelFrequencyCorrection(long correction) + { + mLog.debug("Request to set frequency correction: " + correction); + } + + @Override + public long getChannelFrequencyCorrection() + { + return 0; + } + + @Override + public void setListener(Listener complexBufferListener) + { + mComplexBufferListener = complexBufferListener; + } + + @Override + public void removeListener(Listener listener) + { + mComplexBufferListener = null; + } + + @Override + protected void processSamples() + { + mBufferQueue.drainTo(mBuffersToProcess); + + for(ReusableComplexBuffer buffer: mBuffersToProcess) + { + if(mComplexBufferListener != null) + { + mComplexBufferListener.receive(buffer); + } + else + { + buffer.decrementUserCount(); + } + } + + mBuffersToProcess.clear(); + } + + @Override + public double getSampleRate() + { + return mTunerController.getSampleRate(); + } + + @Override + public void receive(ReusableComplexBuffer reusableComplexBuffer) + { + mBufferQueue.offer(reusableComplexBuffer); + } +} diff --git a/src/main/java/io/github/dsheirer/source/tuner/channel/TunerChannelSource.java b/src/main/java/io/github/dsheirer/source/tuner/channel/TunerChannelSource.java index e5c232262..ce22073f2 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/channel/TunerChannelSource.java +++ b/src/main/java/io/github/dsheirer/source/tuner/channel/TunerChannelSource.java @@ -1,21 +1,23 @@ /* - * ****************************************************************************** - * sdrtrunk - * 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ***************************************************************************** */ package io.github.dsheirer.source.tuner.channel; @@ -289,50 +291,57 @@ public void start() @Override public void run() { - if(!mStopped) + try { - try + if(!mStopped) { - getHeartbeatManager().broadcast(); + try + { + getHeartbeatManager().broadcast(); + } + catch(Throwable t) + { + mLog.error("Error while sending heartbeat", t); + } } - catch(Throwable t) - { - mLog.error("Error while sending heartbeat", t); - } - } - if(!mStopped) - { - try + if(!mStopped) { - processSamples(); + try + { + processSamples(); + } + catch(Throwable t) + { + mLog.error("Error while processing samples", t); + } } - catch(Throwable t) - { - mLog.error("Error while processing samples", t); - } - } - if(mStopped) - { - if(mScheduledFuture != null) + if(mStopped) { - //Set may-interrupt to false so that we can complete this iteration - mScheduledFuture.cancel(false); - } + if(mScheduledFuture != null) + { + //Set may-interrupt to false so that we can complete this iteration + mScheduledFuture.cancel(false); + } - mScheduledFuture = null; + mScheduledFuture = null; - try - { - getHeartbeatManager().broadcast(); - performDisposal(); - } - catch(Throwable t) - { - mLog.error("Error during final shutdown processing of samples", t); + try + { + getHeartbeatManager().broadcast(); + performDisposal(); + } + catch(Throwable t) + { + mLog.error("Error during final shutdown processing of samples", t); + } } } + catch(Throwable t) + { + mLog.error("Error during heartbeat processing", t); + } } } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfiguration.java index 876773e0f..04551aeef 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfiguration.java @@ -1,18 +1,23 @@ /* - * ********************************************************************************************************************* - * sdrtrunk - * Copyright (C) 2014-2017 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * ********************************************************************************************************************* */ package io.github.dsheirer.source.tuner.configuration; @@ -26,6 +31,7 @@ import io.github.dsheirer.source.tuner.fcd.proV1.FCD1TunerConfiguration; import io.github.dsheirer.source.tuner.fcd.proplusV2.FCD2TunerConfiguration; import io.github.dsheirer.source.tuner.hackrf.HackRFTunerConfiguration; +import io.github.dsheirer.source.tuner.recording.RecordingTunerConfiguration; import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerConfiguration; import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerConfiguration; @@ -39,6 +45,7 @@ @JsonSubTypes.Type(value=FCD1TunerConfiguration.class, name="fcd1TunerConfiguration"), @JsonSubTypes.Type(value=FCD2TunerConfiguration.class, name="fcd2TunerConfiguration"), @JsonSubTypes.Type(value=HackRFTunerConfiguration.class, name="hackRFTunerConfiguration"), + @JsonSubTypes.Type(value= RecordingTunerConfiguration.class, name="recordingTunerConfiguration"), @JsonSubTypes.Type(value=R820TTunerConfiguration.class, name="r820TTunerConfiguration"), }) @JacksonXmlRootElement( localName = "tuner_configuration" ) diff --git a/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfigurationFactory.java b/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfigurationFactory.java index 71f8a164c..92f6763a0 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfigurationFactory.java +++ b/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfigurationFactory.java @@ -1,20 +1,24 @@ -/******************************************************************************* - * SDR Trunk - * Copyright (C) 2014-2016 Dennis Sheirer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - ******************************************************************************/ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ package io.github.dsheirer.source.tuner.configuration; @@ -32,6 +36,9 @@ import io.github.dsheirer.source.tuner.hackrf.HackRFTuner; import io.github.dsheirer.source.tuner.hackrf.HackRFTunerConfiguration; import io.github.dsheirer.source.tuner.hackrf.HackRFTunerEditor; +import io.github.dsheirer.source.tuner.recording.RecordingTuner; +import io.github.dsheirer.source.tuner.recording.RecordingTunerConfiguration; +import io.github.dsheirer.source.tuner.recording.RecordingTunerConfigurationEditor; import io.github.dsheirer.source.tuner.rtl.RTL2832Tuner; import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerConfiguration; import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerEditor; @@ -40,55 +47,59 @@ public class TunerConfigurationFactory { - /** - * Creates a tuner configuration for the specified tuner type, unique ID and name - */ - public static TunerConfiguration getTunerConfiguration(TunerType type, String uniqueID, - String name ) - { - switch( type ) - { - case AIRSPY_R820T: - return new AirspyTunerConfiguration( uniqueID, name ); - case ELONICS_E4000: - return new E4KTunerConfiguration( uniqueID, name ); - case FUNCUBE_DONGLE_PRO: - return new FCD1TunerConfiguration( uniqueID, name ); - case FUNCUBE_DONGLE_PRO_PLUS: - return new FCD2TunerConfiguration( uniqueID, name ); - case HACKRF: - return new HackRFTunerConfiguration( uniqueID, name ); - case RAFAELMICRO_R820T: - return new R820TTunerConfiguration( uniqueID, name ); - default: - throw new IllegalArgumentException( "Unrecognized tuner type [" - + type.name() + "] - can't create named [" + name + "] tuner" - + " configuration" ); - } - } - - /** - * Creates a tuner editor gui for the specified tuner - */ - public static Editor getEditor(Tuner tuner, TunerConfigurationModel model ) + /** + * Creates a tuner configuration for the specified tuner type, unique ID and name + */ + public static TunerConfiguration getTunerConfiguration(TunerType type, String uniqueID, + String name) { - switch( tuner.getTunerType() ) - { - case AIRSPY_R820T: - return new AirspyTunerEditor( model, (AirspyTuner)tuner ); - case ELONICS_E4000: - return new E4KTunerEditor( model, (RTL2832Tuner)tuner ); - case FUNCUBE_DONGLE_PRO: - return new FCD1TunerEditor( model, (FCDTuner)tuner ); - case FUNCUBE_DONGLE_PRO_PLUS: - return new FCD2TunerEditor( model, (FCDTuner)tuner ); - case HACKRF: - return new HackRFTunerEditor( model, (HackRFTuner)tuner ); - case RAFAELMICRO_R820T: - return new R820TTunerEditor( model, (RTL2832Tuner)tuner ); - case UNKNOWN: - default: - throw new IllegalArgumentException( "Unrecognized Tuner: " + tuner.getName() ); - } + switch(type) + { + case AIRSPY_R820T: + return new AirspyTunerConfiguration(uniqueID, name); + case ELONICS_E4000: + return new E4KTunerConfiguration(uniqueID, name); + case FUNCUBE_DONGLE_PRO: + return new FCD1TunerConfiguration(uniqueID, name); + case FUNCUBE_DONGLE_PRO_PLUS: + return new FCD2TunerConfiguration(uniqueID, name); + case HACKRF: + return new HackRFTunerConfiguration(uniqueID, name); + case RAFAELMICRO_R820T: + return new R820TTunerConfiguration(uniqueID, name); + case RECORDING: + return new RecordingTunerConfiguration(uniqueID, name); + default: + throw new IllegalArgumentException("Unrecognized tuner type [" + + type.name() + "] - can't create named [" + name + "] tuner" + + " configuration"); + } + } + + /** + * Creates a tuner editor gui for the specified tuner + */ + public static Editor getEditor(Tuner tuner, TunerConfigurationModel model) + { + switch(tuner.getTunerType()) + { + case AIRSPY_R820T: + return new AirspyTunerEditor(model, (AirspyTuner)tuner); + case ELONICS_E4000: + return new E4KTunerEditor(model, (RTL2832Tuner)tuner); + case FUNCUBE_DONGLE_PRO: + return new FCD1TunerEditor(model, (FCDTuner)tuner); + case FUNCUBE_DONGLE_PRO_PLUS: + return new FCD2TunerEditor(model, (FCDTuner)tuner); + case HACKRF: + return new HackRFTunerEditor(model, (HackRFTuner)tuner); + case RAFAELMICRO_R820T: + return new R820TTunerEditor(model, (RTL2832Tuner)tuner); + case RECORDING: + return new RecordingTunerConfigurationEditor(model, (RecordingTuner)tuner); + case UNKNOWN: + default: + throw new IllegalArgumentException("Unrecognized Tuner: " + tuner.getName()); + } } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/manager/PassThroughSourceManager.java b/src/main/java/io/github/dsheirer/source/tuner/manager/PassThroughSourceManager.java new file mode 100644 index 000000000..549c956e8 --- /dev/null +++ b/src/main/java/io/github/dsheirer/source/tuner/manager/PassThroughSourceManager.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * sdr-trunk + * 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 + * + ******************************************************************************/ + +package io.github.dsheirer.source.tuner.manager; + +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.source.SourceEvent; +import io.github.dsheirer.source.SourceException; +import io.github.dsheirer.source.tuner.TunerController; +import io.github.dsheirer.source.tuner.channel.ChannelSpecification; +import io.github.dsheirer.source.tuner.channel.PassThroughChannelSource; +import io.github.dsheirer.source.tuner.channel.TunerChannel; +import io.github.dsheirer.source.tuner.channel.TunerChannelSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * + */ +public class PassThroughSourceManager extends ChannelSourceManager +{ + private final static Logger mLog = LoggerFactory.getLogger(PassThroughSourceManager.class); + private TunerController mTunerController; + private SortedSet mTunerChannels = new TreeSet<>(); + + public PassThroughSourceManager(TunerController tunerController) + { + mTunerController = tunerController; + } + + @Override + public SortedSet getTunerChannels() + { + return mTunerChannels; + } + + @Override + public int getTunerChannelCount() + { + return mTunerChannels.size(); + } + + @Override + public TunerChannelSource getSource(TunerChannel tunerChannel, ChannelSpecification channelSpecification) + { + PassThroughChannelSource channelSource = new PassThroughChannelSource(new SourceEventProxy(), + mTunerController, tunerChannel); + + mLog.debug("Returning a pass through channel"); + mTunerChannels.add(tunerChannel); + + return channelSource; + } + + @Override + public void process(SourceEvent event) throws SourceException + { + switch(event.getEvent()) + { + case REQUEST_START_SAMPLE_STREAM: + if(event.hasSource() && event.getSource() instanceof PassThroughChannelSource) + { + mTunerController.addBufferListener((PassThroughChannelSource)event.getSource()); + } + break; + case REQUEST_STOP_SAMPLE_STREAM: + if(event.hasSource() && event.getSource() instanceof PassThroughChannelSource) + { + mTunerController.removeBufferListener((PassThroughChannelSource)event.getSource()); + } + break; + default: + mLog.debug("Got source event: " + event); + } + } + + public class SourceEventProxy implements Listener + { + @Override + public void receive(SourceEvent sourceEvent) + { + try + { + process(sourceEvent); + } + catch(SourceException se) + { + mLog.error("Error", se); + } + } + } +} diff --git a/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTuner.java b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTuner.java new file mode 100644 index 000000000..62e8061c1 --- /dev/null +++ b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTuner.java @@ -0,0 +1,144 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.source.tuner.recording; + +import io.github.dsheirer.preference.UserPreferences; +import io.github.dsheirer.preference.source.ChannelizerType; +import io.github.dsheirer.source.SourceEvent; +import io.github.dsheirer.source.tuner.Tuner; +import io.github.dsheirer.source.tuner.TunerClass; +import io.github.dsheirer.source.tuner.TunerType; +import io.github.dsheirer.source.tuner.manager.ChannelSourceManager; +import io.github.dsheirer.source.tuner.manager.HeterodyneChannelSourceManager; +import io.github.dsheirer.source.tuner.manager.PassThroughSourceManager; +import io.github.dsheirer.source.tuner.manager.PolyphaseChannelSourceManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Tuner that replays a recorded I/Q baseband recording + */ +public class RecordingTuner extends Tuner +{ + private final static Logger mLog = LoggerFactory.getLogger(RecordingTuner.class); + private static int mInstanceCounter = 1; + private final int mInstanceID = mInstanceCounter++; + private UserPreferences mUserPreferences; + + public RecordingTuner(UserPreferences userPreferences) + { + super("Recording Tuner", new RecordingTunerController()); + + mUserPreferences = userPreferences; + + ChannelSourceManager channelSourceManager = null; + + if(getTunerController().getCurrentSampleRate() < 100000.0d) + { + setChannelSourceManager(new PassThroughSourceManager(getTunerController())); + } + else + { + ChannelizerType channelizerType = userPreferences.getTunerPreference().getChannelizerType(); + + mLog.debug("Using Channelizer Type: " + channelizerType); + + if(channelizerType == ChannelizerType.POLYPHASE) + { + setChannelSourceManager(new PolyphaseChannelSourceManager(getTunerController())); + } + else if(channelizerType == ChannelizerType.HETERODYNE) + { + setChannelSourceManager(new HeterodyneChannelSourceManager(getTunerController())); + } + else + { + throw new IllegalArgumentException("Unrecognized channelizer type: " + channelizerType); + } + } + } + + /** + * Returns the tuner controller cast as a test tuner controller. + */ + public RecordingTunerController getTunerController() + { + return (RecordingTunerController)super.getTunerController(); + } + + @Override + public String getUniqueID() + { + return getName() + "-" + mInstanceID; + } + + @Override + public TunerClass getTunerClass() + { + return TunerClass.RECORDING_TUNER; + } + + @Override + public TunerType getTunerType() + { + return TunerClass.RECORDING_TUNER.getTunerType(); + } + + @Override + public double getSampleSize() + { + return 16.0; + } + + @Override + public void process(SourceEvent event) + { + super.process(event); + + if(event.getEvent() == SourceEvent.Event.NOTIFICATION_RECORDING_FILE_LOADED) + { + if(getTunerController().getCurrentSampleRate() < 100000.0d) + { + setChannelSourceManager(new PassThroughSourceManager(getTunerController())); + } + else + { + ChannelizerType channelizerType = mUserPreferences.getTunerPreference().getChannelizerType(); + + mLog.debug("Using Channelizer Type: " + channelizerType); + + if(channelizerType == ChannelizerType.POLYPHASE) + { + setChannelSourceManager(new PolyphaseChannelSourceManager(getTunerController())); + } + else if(channelizerType == ChannelizerType.HETERODYNE) + { + setChannelSourceManager(new HeterodyneChannelSourceManager(getTunerController())); + } + else + { + throw new IllegalArgumentException("Unrecognized channelizer type: " + channelizerType); + } + } + } + } +} diff --git a/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerConfiguration.java new file mode 100644 index 000000000..0d211a1b6 --- /dev/null +++ b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerConfiguration.java @@ -0,0 +1,63 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.source.tuner.recording; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import io.github.dsheirer.source.tuner.TunerType; +import io.github.dsheirer.source.tuner.configuration.TunerConfiguration; + +/** + * Recording tuner configuration for using baseband I/Q recordings as a tuner source + */ +public class RecordingTunerConfiguration extends TunerConfiguration +{ + private String mPath; + + public RecordingTunerConfiguration() + { + //Empty jackson constructor + } + + public RecordingTunerConfiguration(String uniqueId, String name) + { + super(uniqueId, name); + } + + @JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance") + @Override + public TunerType getTunerType() + { + return TunerType.RECORDING; + } + + @JacksonXmlProperty(isAttribute = true, localName = "path") + public String getPath() + { + return mPath; + } + + public void setPath(String path) + { + mPath = path; + } +} diff --git a/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerConfigurationEditor.java b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerConfigurationEditor.java new file mode 100644 index 000000000..b9ee84637 --- /dev/null +++ b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerConfigurationEditor.java @@ -0,0 +1,222 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.source.tuner.recording; + +import io.github.dsheirer.source.SourceException; +import io.github.dsheirer.source.tuner.configuration.TunerConfiguration; +import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEditor; +import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEvent; +import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel; +import net.miginfocom.swing.MigLayout; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JTextField; +import javax.swing.filechooser.FileFilter; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.io.File; + +public class RecordingTunerConfigurationEditor extends TunerConfigurationEditor +{ + private static final long serialVersionUID = 1L; + + private final static Logger mLog = LoggerFactory.getLogger(RecordingTunerConfigurationEditor.class); + + private JTextField mConfigurationName; + private JButton mRecordingChooserButton; + private JLabel mRecordingPath; + private boolean mLoading; + + private RecordingTunerController mController; + + public RecordingTunerConfigurationEditor(TunerConfigurationModel tunerConfigurationModel, RecordingTuner tuner) + { + super(tunerConfigurationModel); + + mController = tuner.getTunerController(); + + init(); + } + + @Override + public void setTunerLockState(boolean locked) + { + setControlsEnabled(!locked); + } + + private RecordingTunerConfiguration getConfiguration() + { + if(hasItem()) + { + return (RecordingTunerConfiguration)getItem(); + } + + return null; + } + + private void init() + { + setLayout(new MigLayout("fill,wrap 4", "[right][grow,fill][right][grow,fill]", + "[][][][][][][grow]")); + + add(new JLabel("Recording Tuner Configuration"), "span,align center"); + + mConfigurationName = new JTextField(); + mConfigurationName.setEnabled(false); + mConfigurationName.addFocusListener(new FocusListener() + { + @Override + public void focusLost(FocusEvent e) + { + save(); + } + + @Override + public void focusGained(FocusEvent e) + { + } + }); + + add(new JLabel("Name:")); + add(mConfigurationName, "span, wrap"); + + mRecordingChooserButton = new JButton("Recording"); + mRecordingChooserButton.setEnabled(false); + mRecordingChooserButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + final JFileChooser chooser = new JFileChooser(); + chooser.setFileFilter(new FileFilter() + { + @Override + public boolean accept(File f) + { + return f.isDirectory() || f.getName().matches(".*.wav"); + } + + @Override + public String getDescription() + { + return "Baseband Recordings (*.wav)"; + } + }); + int returnVal = chooser.showOpenDialog(RecordingTunerConfigurationEditor.this); + + if (returnVal == JFileChooser.APPROVE_OPTION) + { + File file = chooser.getSelectedFile(); + + if(file != null) + { + mRecordingPath.setText(file.getAbsolutePath()); + save(); + } + } + } + }); + add(mRecordingChooserButton); + + mRecordingPath = new JLabel(); + add(mRecordingPath); + } + + /** + * Sets each of the tuner configuration controls to the enabled argument state + */ + private void setControlsEnabled(boolean enabled) + { + if(mConfigurationName.isEnabled() != enabled) + { + mConfigurationName.setEnabled(enabled); + } + + if(mRecordingChooserButton.isEnabled() != enabled) + { + mRecordingChooserButton.setEnabled(enabled); + } + } + + @Override + public void setItem(TunerConfiguration tunerConfiguration) + { + super.setItem(tunerConfiguration); + + //Toggle loading so that we don't fire a change event and schedule a settings file save + mLoading = true; + + if(hasItem()) + { + RecordingTunerConfiguration config = getConfiguration(); + + setControlsEnabled(tunerConfiguration.isAssigned()); + mConfigurationName.setText(config.getName()); + mRecordingPath.setText(config.getPath()); + } + else + { + setControlsEnabled(false); + mConfigurationName.setText(""); + mRecordingPath.setText(""); + } + + mLoading = false; + } + + @Override + public void save() + { + if(hasItem() && !mLoading) + { + RecordingTunerConfiguration config = getConfiguration(); + + config.setName(mConfigurationName.getText()); + + String path = mRecordingPath.getText(); + + if(path != null && !path.isEmpty()) + { + config.setPath(path); + + mLog.debug("Saving and setting controller with path: " + path); + try + { + mController.apply(config); + } + catch(SourceException se) + { + mLog.error("Error while applying recording tuner configuration", se); + } + } + + getTunerConfigurationModel().broadcast( + new TunerConfigurationEvent(getConfiguration(), TunerConfigurationEvent.Event.CHANGE)); + } + } +} \ No newline at end of file diff --git a/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerController.java new file mode 100644 index 000000000..e6cebe78d --- /dev/null +++ b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerController.java @@ -0,0 +1,233 @@ +/* + * + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** + * + * + */ +package io.github.dsheirer.source.tuner.recording; + +import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.sample.buffer.ReusableComplexBuffer; +import io.github.dsheirer.source.SourceEvent; +import io.github.dsheirer.source.SourceException; +import io.github.dsheirer.source.tuner.TunerController; +import io.github.dsheirer.source.tuner.configuration.TunerConfiguration; +import io.github.dsheirer.source.wave.ComplexWaveSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sound.sampled.UnsupportedAudioFileException; +import java.io.File; +import java.io.IOException; + +public class RecordingTunerController extends TunerController +{ + private final static Logger mLog = LoggerFactory.getLogger(RecordingTunerController.class); + + public static final int DC_NOISE_BANDWIDTH = 0; + public static final double USABLE_BANDWIDTH_PERCENTAGE = 1.00; + private ComplexWaveSource mComplexWaveSource; + private long mCenterFrequency; + private boolean mRunning; + + /** + * Tuner controller testing implementation. + */ + public RecordingTunerController() + { + super(1000000l, 3000000000l, DC_NOISE_BANDWIDTH, USABLE_BANDWIDTH_PERCENTAGE); + } + + /** + * Sets the recording file and center frequency for this controller + * @param recordingPath to play + * @param centerFrequency of the recording + * @throws IOException if there are any errors + */ + private void setRecording(String recordingPath, long centerFrequency) throws IOException + { + if(mComplexWaveSource != null) + { + mComplexWaveSource.close(); + mComplexWaveSource = null; + } + + if(recordingPath == null) + { + return; + } + + mComplexWaveSource = new ComplexWaveSource(new File(recordingPath), true); + mComplexWaveSource.setListener(new Listener() + { + @Override + public void receive(ReusableComplexBuffer reusableComplexBuffer) + { + //Send to parent class to broadcast to listeners + broadcast(reusableComplexBuffer); + } + }); + + try + { + mComplexWaveSource.open(); + mLog.info("Tuner Recording Loaded: " + recordingPath); + } + catch(UnsupportedAudioFileException e) + { + mLog.error("Unsupported audio format", e); + } + + + mCenterFrequency = centerFrequency; + + mLog.debug("Set recording center frequency to: " + mCenterFrequency); + + if(mCenterFrequency == 0) + { + mCenterFrequency = 100000000; + } + + try + { + mFrequencyController.setFrequency(mCenterFrequency); + mFrequencyController.setSampleRate((int)mComplexWaveSource.getSampleRate()); + mFrequencyController.broadcast(SourceEvent.recordingFileLoaded()); + } + catch(SourceException e) + { + throw new IOException("Can't set frequency or sample rate", e); + } + } + + @Override + public int getBufferSampleCount() + { + if(mComplexWaveSource != null) + { + return mComplexWaveSource.getBufferSampleCount(); + } + + return 0; + } + + + + @Override + public void dispose() + { + //no-op + } + + @Override + public void addBufferListener(Listener listener) + { + super.addBufferListener(listener); + + if(mComplexWaveSource != null) + { + if(!mRunning) + { + mComplexWaveSource.start(); + mRunning = true; + } + } + } + + @Override + public void removeBufferListener(Listener listener) + { + super.removeBufferListener(listener); + + if(!mReusableBufferBroadcaster.hasListeners() && mComplexWaveSource != null) + { + mComplexWaveSource.setListener((Listener)null); + mComplexWaveSource.stop(); + mRunning = false; + } + } + + @Override + public void apply(TunerConfiguration config) throws SourceException + { + if(config instanceof RecordingTunerConfiguration) + { + RecordingTunerConfiguration rtc = (RecordingTunerConfiguration)config; + + mCenterFrequency = rtc.getFrequency(); + + try + { + setRecording(rtc.getPath(), rtc.getFrequency()); + } + catch(IOException ioe) + { + mLog.debug("Error loading recording tuner baseband recording: " + rtc.getPath(), ioe); + } + } + } + + @Override + public void setFrequency(long frequency) throws SourceException + { +// if(hasBufferListeners()) +// { + mLog.debug("Set frequency [" + frequency + "] request ignored"); +// } +// else +// { +// super.setFrequency(frequency); +// } + } + + /** + * Current center frequency for this tuner + * @throws SourceException + */ + @Override + public long getTunedFrequency() throws SourceException + { + return mCenterFrequency; + } + + /** + * Sets the center frequency for this tuner + * @param frequency in hertz + * @throws SourceException + */ + @Override + public void setTunedFrequency(long frequency) throws SourceException + { + mLog.debug("Set frequency [" + frequency + "] request ignored"); +// mCenterFrequency = frequency; + } + + /** + * Current sample rate for this tuner controller + */ + @Override + public double getCurrentSampleRate() + { + if(mComplexWaveSource != null) + { + return mComplexWaveSource.getSampleRate(); + } + + return 0d; + } +} diff --git a/src/main/java/io/github/dsheirer/source/wave/ComplexWaveSource.java b/src/main/java/io/github/dsheirer/source/wave/ComplexWaveSource.java index 72abaa84f..cf8bb760c 100644 --- a/src/main/java/io/github/dsheirer/source/wave/ComplexWaveSource.java +++ b/src/main/java/io/github/dsheirer/source/wave/ComplexWaveSource.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 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. + * * ****************************************************************************** + * * 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 + * * ***************************************************************************** * - * 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 - * - ******************************************************************************/ + */ package io.github.dsheirer.source.wave; import io.github.dsheirer.sample.ConversionUtils; @@ -23,6 +29,7 @@ import io.github.dsheirer.source.IControllableFileSource; import io.github.dsheirer.source.IFrameLocationListener; import io.github.dsheirer.source.SourceEvent; +import io.github.dsheirer.util.ThreadPool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,6 +40,8 @@ import java.io.File; import java.io.IOException; import java.util.Arrays; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; public class ComplexWaveSource extends ComplexSource implements IControllableFileSource, AutoCloseable { @@ -46,10 +55,28 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil private AudioInputStream mInputStream; private File mFile; private ReusableComplexBufferQueue mReusableComplexBufferQueue = new ReusableComplexBufferQueue("ComplexWaveSource"); + private boolean mAutoReplay; + private ScheduledFuture mReplayController; - public ComplexWaveSource(File file) throws IOException + /** + * Constructs an instance with optional auto-replay at near real time. + * @param file containing complex I/Q sample data + * @param autoReplay to enable continuous looping, real-time playback of sample data + */ + public ComplexWaveSource(File file, boolean autoReplay) throws IOException { + if(file == null || !file.exists() || !supports(file)) + { + throw new IOException("Empty or Unsupported file format"); + } + mFile = file; + mAutoReplay = autoReplay; + } + + public ComplexWaveSource(File file) throws IOException + { + this(file, false); } @Override @@ -75,19 +102,41 @@ public Listener getSourceEventListener() public void reset() { stop(); + mFrameCounter = 0; start(); } + /** + * Number of samples per buffer + */ + public int getBufferSampleCount() + { + return (int)(getSampleRate() / 20.0d); + } + @Override public void start() { - try + if(mInputStream == null) { - open(); + try + { + open(); + } + catch(Exception e) + { + mLog.error("Error", e); + } } - catch(IOException | UnsupportedAudioFileException e) + + if(mAutoReplay) { - mLog.error("Error starting complex wave source"); + long intervalMilliseconds = 50; //20 intervals per second + double framesPerInterval = getSampleRate() / 20.0d; + mReplayController = ThreadPool.SCHEDULED.scheduleAtFixedRate(new ReplayController(framesPerInterval), + 0, intervalMilliseconds, TimeUnit.MILLISECONDS); + + } } @@ -96,6 +145,11 @@ public void stop() { try { + if(mReplayController != null) + { + mReplayController.cancel(true); + } + close(); } catch(IOException e) @@ -159,27 +213,22 @@ public void open() throws IOException, UnsupportedAudioFileException if(mInputStream == null) { mInputStream = AudioSystem.getAudioInputStream(mFile); - } - else - { - throw new IOException("Can't open wave source - is already opened"); - } + AudioFormat format = mInputStream.getFormat(); - AudioFormat format = mInputStream.getFormat(); + mBytesPerFrame = format.getFrameSize(); - mBytesPerFrame = format.getFrameSize(); + if(format.getChannels() != 2 || format.getSampleSizeInBits() != 16) + { + throw new IOException("Unsupported Wave Format - EXPECTED: 2 " + + "channels 16-bit samples FOUND: " + + mInputStream.getFormat().getChannels() + " channels " + + mInputStream.getFormat().getSampleSizeInBits() + "-bit samples"); + } - if(format.getChannels() != 2 || format.getSampleSizeInBits() != 16) - { - throw new IOException("Unsupported Wave Format - EXPECTED: 2 " + - "channels 16-bit samples FOUND: " + - mInputStream.getFormat().getChannels() + " channels " + - mInputStream.getFormat().getSampleSizeInBits() + "-bit samples"); + /* Broadcast that we're at frame location 0 */ + broadcast(0); } - - /* Broadcast that we're at frame location 0 */ - broadcast(0); } /** @@ -192,7 +241,7 @@ public void next(int frames) throws IOException } /** - * Reads the number of frames and optionally sends the buffer to the listener + * Reads the number of frames and optionally sends the buffer(s) to the listener */ public void next(int frames, boolean broadcast) throws IOException { @@ -302,4 +351,34 @@ public static boolean supports(File file) return false; } + + public class ReplayController implements Runnable + { + private double mFramesPerInterval; + private int mFramesRead; + private int mIntervals; + + public ReplayController(double framesPerInterval) + { + mFramesPerInterval = framesPerInterval; + } + + @Override + public void run() + { + mIntervals++; + int framesToRead = (int)Math.floor((mIntervals * mFramesPerInterval) - mFramesRead); + + try + { + next(framesToRead, true); + mFramesRead += framesToRead; + } + catch(IOException ioe) + { + mLog.debug("End of Recording - looping [" + ioe.getLocalizedMessage() + "]"); + reset(); + } + } + } }