diff --git a/src/main/java/io/github/dsheirer/message/StuffBitsMessage.java b/src/main/java/io/github/dsheirer/message/StuffBitsMessage.java new file mode 100644 index 00000000..9d903b0d --- /dev/null +++ b/src/main/java/io/github/dsheirer/message/StuffBitsMessage.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.message; + +import io.github.dsheirer.identifier.Identifier; +import io.github.dsheirer.protocol.Protocol; + +import java.util.Collections; +import java.util.List; + +/** + * Empty message to convey that a number of stuff/tail bits were processed with no sync or valid message detected. + * + * This message supports periodic updates to external processor(s) that may be tracking bit error rates. + */ +public class StuffBitsMessage extends Message +{ + private int mBitsProcessed; + private Protocol mProtocol; + + /** + * Constructs a sync loss message. + * + * @param timestamp of the message + * @param bitsProcessed without a sync pattern detection of message decode + */ + public StuffBitsMessage(long timestamp, int bitsProcessed, Protocol protocol) + { + super(timestamp); + mBitsProcessed = bitsProcessed; + mProtocol = protocol; + } + + /** + * Indicates the number of bits that were processed without a sync dectection or message decode + */ + public int getBitsProcessed() + { + return mBitsProcessed; + } + + @Override + public String toString() + { + return "<-> TAIL/STUFF BITS PROCESSED [" + getBitsProcessed() + "]"; + } + + @Override + public boolean isValid() + { + return true; + } + + @Override + public Protocol getProtocol() + { + return mProtocol; + } + + @Override + public List getIdentifiers() + { + return Collections.EMPTY_LIST; + } +} 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 3fb2cf1c..71bc630a 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 @@ -23,6 +23,7 @@ package io.github.dsheirer.module.decode.event; import io.github.dsheirer.filter.FilterSet; import io.github.dsheirer.message.IMessage; +import io.github.dsheirer.message.StuffBitsMessage; import io.github.dsheirer.sample.Listener; import javax.swing.table.AbstractTableModel; @@ -114,6 +115,12 @@ public class MessageActivityModel extends AbstractTableModel implements Listener public void receive(final IMessage message) { + //Don't process tail bits or stuff bits message fragments + if(message instanceof StuffBitsMessage) + { + return; + } + if(mMessageFilter.passes(message)) { final MessageItem messageItem = new MessageItem(message); diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageFramer.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageFramer.java index d660ed29..07666bdb 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageFramer.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageFramer.java @@ -28,16 +28,18 @@ 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.StuffBitsMessage; import io.github.dsheirer.message.SyncLossMessage; import io.github.dsheirer.module.decode.DecoderType; -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.module.decode.p25.phase2.P25P2MessageFramer; +import io.github.dsheirer.module.decode.p25.phase2.P25P2MessageProcessor; +import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameters; import io.github.dsheirer.protocol.Protocol; import io.github.dsheirer.record.binary.BinaryReader; import io.github.dsheirer.sample.Listener; @@ -45,8 +47,12 @@ import io.github.dsheirer.sample.buffer.ReusableByteBuffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.function.Consumer; /** * P25 Sync Detector and Message Framer. Includes capability to detect PLL out-of-phase lock errors @@ -59,7 +65,6 @@ public class P25P1MessageFramer implements Listener, IP25P1DataUnitDetect private P25P1DataUnitDetector mDataUnitDetector; private P25P1ChannelStatusProcessor mChannelStatusProcessor = new P25P1ChannelStatusProcessor(); private Listener mMessageListener; - private boolean mAssemblingMessage = false; private CorrectedBinaryMessage mBinaryMessage; private P25P1DataUnitID mDataUnitID; @@ -422,58 +427,101 @@ public class P25P1MessageFramer implements Listener, IP25P1DataUnitDetect if(bitsProcessed > 0 && mMessageListener != null) { - mMessageListener.receive(new SyncLossMessage(getTimestamp(), bitsProcessed, Protocol.APCO25)); + if(bitsProcessed < 64) + { + mMessageListener.receive(new StuffBitsMessage(getTimestamp(), bitsProcessed, Protocol.APCO25)); + } + else + { + mMessageListener.receive(new SyncLossMessage(getTimestamp(), bitsProcessed, Protocol.APCO25)); + } } } public static void main(String[] args) { - P25P1DecoderLSM decoderLSM = new P25P1DecoderLSM(); + Path directory = Paths.get("/media/denny/500G1EXT4/RadioRecordings/Harris APCO25 Phase II"); +// Path directory = Paths.get("/media/denny/500G1EXT4/PBITRecordings"); + final boolean phase1 = false; -// 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"); - - P25P1MessageFramer messageFramer = new P25P1MessageFramer(null, DecoderType.P25_PHASE1.getProtocol().getBitRate()); - - try(BinaryReader reader = new BinaryReader(path, 200)) + try { - while(reader.hasNext()) - { - messageFramer.receive(reader.next()); - } + DirectoryStream stream = Files.newDirectoryStream(directory, "*Hills*TRAFFIC.bits"); + + stream.forEach(new Consumer() + { + @Override + public void accept(Path path) + { + mLog.debug("Processing:" + path.toString()); + + if(phase1) + { + P25P1MessageFramer messageFramer = new P25P1MessageFramer(null, DecoderType.P25_PHASE1.getProtocol().getBitRate()); + P25P1MessageProcessor messageProcessor = new P25P1MessageProcessor(); + messageFramer.setListener(messageProcessor); + messageProcessor.setMessageListener(new Listener() + { + @Override + public void receive(IMessage message) + { + if(!(message instanceof StuffBitsMessage)) + { + mLog.debug(message.toString()); + } + } + }); + + try(BinaryReader reader = new BinaryReader(path, 200)) + { + while(reader.hasNext()) + { + ReusableByteBuffer buffer = reader.next(); + messageFramer.receive(buffer); + } + } + catch(Exception ioe) + { + ioe.printStackTrace(); + } + } + else + { + P25P2MessageFramer messageFramer = new P25P2MessageFramer(null, DecoderType.P25_PHASE2.getProtocol().getBitRate()); + ScrambleParameters scrambleParameters = new ScrambleParameters(123654, 813, 10); //Hills County + messageFramer.setScrambleParameters(scrambleParameters); + P25P2MessageProcessor messageProcessor = new P25P2MessageProcessor(); + messageFramer.setListener(messageProcessor); + messageProcessor.setMessageListener(new Listener() + { + @Override + public void receive(IMessage message) + { + mLog.debug(message.toString()); + } + }); + + try(BinaryReader reader = new BinaryReader(path, 200)) + { + while(reader.hasNext()) + { + ReusableByteBuffer buffer = reader.next(); + messageFramer.receive(buffer); + } + } + catch(Exception ioe) + { + ioe.printStackTrace(); + } + } + } + } + ); } - catch(Exception ioe) + catch(IOException ioe) { - ioe.printStackTrace(); + mLog.error("Error", ioe); } - - 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)) - { - while(reader.hasNext()) - { - messageFramer.receive(reader.next()); - } - } - catch(Exception ioe) - { - ioe.printStackTrace(); - } - - frameRecorder.stop(); } }