#1115 Adds more parsing updates for LRRP packets. (#1116)

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
Denny Sheirer
2021-11-27 13:42:04 -05:00
committed by GitHub
parent aa89079e28
commit 2a45849e6d
25 changed files with 878 additions and 131 deletions

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2021 Dennis Sheirer
*
* This 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,11 +19,15 @@
package io.github.dsheirer.identifier.location;
import java.text.DecimalFormat;
/**
* Geospatial point (location)
*/
public class Point
{
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00000");
private double mLatitude;
private double mLongitude;
@@ -52,8 +56,8 @@ public class Point
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(Math.abs(mLatitude)).append(mLatitude >= 0 ? "N " : "S ");
sb.append(Math.abs(mLongitude)).append(mLongitude >= 0 ? "E" : "W");
sb.append(DECIMAL_FORMAT.format(Math.abs(mLatitude))).append(mLatitude >= 0 ? "N " : "S ");
sb.append(DECIMAL_FORMAT.format(Math.abs(mLongitude))).append(mLongitude >= 0 ? "E" : "W");
return sb.toString();
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2021 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,6 +28,10 @@ import io.github.dsheirer.module.decode.dmr.message.CACH;
import io.github.dsheirer.module.decode.dmr.message.DMRBurst;
import io.github.dsheirer.module.decode.dmr.message.DMRMessage;
import io.github.dsheirer.module.decode.dmr.message.DMRMessageFactory;
import io.github.dsheirer.module.decode.dmr.message.data.packet.DMRPacketMessage;
import io.github.dsheirer.module.decode.ip.lrrp.LRRPPacket;
import io.github.dsheirer.module.decode.ip.lrrp.token.Identity;
import io.github.dsheirer.module.decode.ip.lrrp.token.Token;
import io.github.dsheirer.protocol.Protocol;
import io.github.dsheirer.record.binary.BinaryReader;
import io.github.dsheirer.sample.Listener;
@@ -40,6 +44,11 @@ import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
@@ -257,11 +266,20 @@ public class DMRMessageFramer implements Listener<Dibit>, IDMRBurstDetectListene
if(message instanceof DMRBurst && ((DMRBurst)message).hasCACH())
{
CACH cach = ((DMRBurst)message).getCACH();
mLog.info(cach.toString() + " TS:" + message.getTimeslot() + " " + message.toString());
// mLog.info(cach.toString() + " TS:" + message.getTimeslot() + " " + message.toString());
}
else
{
mLog.info(" TS:" + message.getTimeslot() + " " + message.toString());
// mLog.info(" TS:" + message.getTimeslot() + " " + message.toString());
}
if(message instanceof DMRPacketMessage dpm)
{
if(dpm.getPacket() instanceof LRRPPacket lrrp)
{
mLog.info("LRRP: " + lrrp.toString());
mLog.info("MESSAGE: " + lrrp.getMessage().toHexString());
}
}
// if(message instanceof UDTHeader)
@@ -286,6 +304,80 @@ public class DMRMessageFramer implements Listener<Dibit>, IDMRBurstDetectListene
}
}
public static class LrrpProcessor implements Listener<IMessage>
{
private Map<Integer, List<LRRPPacket>> mLrrpMap = new HashMap<>();
public LrrpProcessor()
{
}
@Override
public void receive(IMessage message)
{
if(message instanceof DMRPacketMessage dpm)
{
if(dpm.getPacket() instanceof LRRPPacket lrrp)
{
process(lrrp);
}
}
}
public void process(LRRPPacket lrrpPacket)
{
Identity identity = getIdentity(lrrpPacket);
if(identity != null)
{
List<LRRPPacket> packets = mLrrpMap.get(identity.getID());
if(packets == null)
{
packets = new ArrayList<>();
}
packets.add(lrrpPacket);
mLrrpMap.put(identity.getID(), packets);
}
}
public void log()
{
mLog.info("*************** DUMPING LRRP PACKETS****************************");
List<Integer> ids = new ArrayList(mLrrpMap.keySet());
Collections.sort(ids);
for(Integer id: ids)
{
mLog.info("");
mLog.info("###################### ID: " + id + " ###################################");
List<LRRPPacket> packets = mLrrpMap.get(id);
for(LRRPPacket lrrp: packets)
{
mLog.info("PACKET: " + lrrp.toString());
mLog.info("MESSAGE: " + lrrp.getMessage().toHexString());
}
}
}
private static Identity getIdentity(LRRPPacket packet)
{
for(Token token: packet.getTokens())
{
if(token instanceof Identity)
{
return (Identity)token;
}
}
return null;
}
}
public static void main(String[] args)
{
String path = "/media/denny/Lexar/Recordings/DMR/";
@@ -334,16 +426,15 @@ public class DMRMessageFramer implements Listener<Dibit>, IDMRBurstDetectListene
// String file = path + "20200730_090634_9600BPS_DMR_Otsego_County_Road_Commission_Alpine_Center_Road_Commission.bits";
//Cap+ BP Scrambling
// String file = path + "20200829_065610_9600BPS_DMR_Albany_Medical_Center_Albany_LCN_3.bits";
String file = "/home/denny/SDRTrunk/recordings/20200927_054837_9600BPS_DMR_Blair_Communications_(Capacity_Plus)_Dallas_Control_9.bits";
String file = path + "20200829_065610_9600BPS_DMR_Albany_Medical_Center_Albany_LCN_3.bits";
// String file = "/home/denny/SDRTrunk/recordings/20200927_054837_9600BPS_DMR_Blair_Communications_(Capacity_Plus)_Dallas_Control_9.bits";
MessageListener listener = new MessageListener();
DecodeConfigDMR config = new DecodeConfigDMR();
LrrpProcessor lrrpProcessor = new LrrpProcessor();
boolean multi = false;
boolean multi = true;
if(multi)
{
@@ -360,7 +451,9 @@ public class DMRMessageFramer implements Listener<Dibit>, IDMRBurstDetectListene
DMRMessageFramer messageFramer = new DMRMessageFramer(null);
DMRMessageProcessor messageProcessor = new DMRMessageProcessor(config);
messageFramer.setListener(messageProcessor);
messageProcessor.setMessageListener(listener);
// messageProcessor.setMessageListener(listener);
messageProcessor.setMessageListener(lrrpProcessor);
try(BinaryReader reader = new BinaryReader(path, 200))
{
@@ -400,6 +493,9 @@ public class DMRMessageFramer implements Listener<Dibit>, IDMRBurstDetectListene
{
ioe.printStackTrace();
}
System.out.println("Logging LRRP Packets ...");
lrrpProcessor.log();
}
else
{

View File

@@ -23,8 +23,10 @@ import io.github.dsheirer.bits.CorrectedBinaryMessage;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.module.decode.ip.IPacket;
import io.github.dsheirer.module.decode.ip.Packet;
import io.github.dsheirer.module.decode.ip.lrrp.token.RequestedTokens;
import io.github.dsheirer.module.decode.ip.lrrp.token.Token;
import io.github.dsheirer.module.decode.ip.lrrp.token.TokenFactory;
import io.github.dsheirer.module.decode.ip.lrrp.token.TokenType;
import java.util.ArrayList;
import java.util.Collections;
@@ -95,6 +97,11 @@ public class LRRPPacket extends Packet
return mTokens;
}
private boolean isResponsePacket()
{
return getHeader().getLRRPPacketType().isResponse();
}
private void parseTokens()
{
if(mTokens == null)
@@ -104,13 +111,55 @@ public class LRRPPacket extends Packet
int characterCount = getHeader().getPayloadLength();
int offset = getOffset() + TOKEN_START;
while(characterCount > 0 && offset < getMessage().size())
if(isResponsePacket())
{
String tokenId = getTokenIdentifier(offset);
Token token = TokenFactory.createToken(tokenId, getMessage(), offset, characterCount);
mTokens.add(token);
characterCount -= token.getByteLength();
offset += (8 * token.getByteLength());
while(characterCount > 0 && offset < getMessage().size())
{
String tokenId = getTokenIdentifier(offset);
Token token = TokenFactory.createToken(tokenId, getMessage(), offset, characterCount);
mTokens.add(token);
characterCount -= token.getByteLength();
offset += (8 * token.getByteLength());
}
}
else
{
String message = getMessage().getSubMessage(getOffset(), getOffset() + ((characterCount + 2) * 8)).toHexString();
int x = 0;
RequestedTokens requestedTokens = new RequestedTokens();
while(characterCount > 0 && offset < getMessage().size())
{
String tokenId = getTokenIdentifier(offset);
TokenType tokenType = TokenType.fromValue(tokenId);
if(tokenType.isRequestParameterToken())
{
Token token = TokenFactory.createToken(tokenId, getMessage(), offset, characterCount);
mTokens.add(token);
characterCount -= token.getByteLength();
offset += (8 * token.getByteLength());
}
else
{
if(tokenType != TokenType.UNKNOWN)
{
requestedTokens.add(tokenType);
}
else
{
requestedTokens.add(tokenId);
}
characterCount -= 1;
offset += (8);
}
}
if(requestedTokens.hasRequestedTokens())
{
mTokens.add(requestedTokens);
}
}
Collections.sort(mTokens, (o1, o2) -> o1.getTokenType().compareTo(o2.getTokenType()));

View File

@@ -24,25 +24,27 @@ package io.github.dsheirer.module.decode.ip.lrrp;
*/
public enum LRRPPacketType
{
IMMEDIATE_LOCATION_REQUEST(0x05, "IMMEDIATE LOCATION REQUEST"),
IMMEDIATE_LOCATION_RESPONSE(0x07, "IMMEDIATE LOCATION RESPONSE"),
TRIGGERED_LOCATION_START_REQUEST(0x09, "TRIGGERED LOCATION START REQUEST"),
TRIGGERED_LOCATION_START_RESPONSE(0x0B, "TRIGGERED LOCATION START RESPONSE"),
TRIGGERED_LOCATION(0x0D, "TRIGGERED LOCATION"),
TRIGGERED_LOCATION_STOP_REQUEST(0x0F, "TRIGGERED LOCATION STOP REQUEST"),
TRIGGERED_LOCATION_STOP_RESPONSE(0x11, "TRIGGERED LOCATION STOP RESPONSE"),
PROTOCOL_VERSION_REQUEST(0x14, "PROTOCOL VERSION REQUEST"),
PROTOCOL_VERSION_RESPONSE(0x15, "PROTOCOL VERSION RESPONSE"),
IMMEDIATE_LOCATION_REQUEST(0x05, "IMMEDIATE LOCATION REQUEST", false),
IMMEDIATE_LOCATION_RESPONSE(0x07, "IMMEDIATE LOCATION RESPONSE", true),
TRIGGERED_LOCATION_START_REQUEST(0x09, "TRIGGERED LOCATION START REQUEST", false),
TRIGGERED_LOCATION_START_RESPONSE(0x0B, "TRIGGERED LOCATION START RESPONSE", true),
TRIGGERED_LOCATION(0x0D, "TRIGGERED LOCATION", true),
TRIGGERED_LOCATION_STOP_REQUEST(0x0F, "TRIGGERED LOCATION STOP REQUEST", false),
TRIGGERED_LOCATION_STOP_RESPONSE(0x11, "TRIGGERED LOCATION STOP RESPONSE", true),
PROTOCOL_VERSION_REQUEST(0x14, "PROTOCOL VERSION REQUEST", false),
PROTOCOL_VERSION_RESPONSE(0x15, "PROTOCOL VERSION RESPONSE", true),
UNKNOWN(-1, "UNKNOWN");
UNKNOWN(-1, "UNKNOWN", false);
private int mValue;
private String mLabel;
private boolean mIsResponse;
LRRPPacketType(int value, String label)
LRRPPacketType(int value, String label, boolean isResponse)
{
mValue = value;
mLabel = label;
mIsResponse = isResponse;
}
/**
@@ -59,6 +61,14 @@ public enum LRRPPacketType
return mLabel;
}
/**
* Indicates if this is a response type
*/
public boolean isResponse()
{
return mIsResponse;
}
/**
* Lookup the LRRP packet type from the value.
* @param value to lookup

View File

@@ -21,13 +21,15 @@ package io.github.dsheirer.module.decode.ip.lrrp.token;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import java.text.DecimalFormat;
/**
* LRRP Geo-Fence Position with latitude, longitude and radius
* LRRP Approximate Position with latitude, longitude and error
*/
public class GeoFencePosition extends Position
public class Circle2d extends Point2d
{
private static final int[] RADIUS_WHOLE = new int[]{72, 73, 74, 75, 76, 77, 78, 79};
private static final int[] RADIUS_FRACTIONAL = new int[]{80, 81, 82, 83, 84, 85, 86, 87};
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00");
private static final int[] RADIUS = new int[]{72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87};
/**
* Constructs an instance of an approximate position token.
@@ -35,7 +37,7 @@ public class GeoFencePosition extends Position
* @param message containing the heading
* @param offset to the start of the token
*/
public GeoFencePosition(CorrectedBinaryMessage message, int offset)
public Circle2d(CorrectedBinaryMessage message, int offset)
{
super(message, offset);
}
@@ -43,7 +45,7 @@ public class GeoFencePosition extends Position
@Override
public TokenType getTokenType()
{
return TokenType.POSITION_GEO_FENCE;
return TokenType.CIRCLE_2D;
}
/**
@@ -53,13 +55,13 @@ public class GeoFencePosition extends Position
*/
public float getRadius()
{
return getFloat(RADIUS_WHOLE, RADIUS_FRACTIONAL);
return getMessage().getInt(RADIUS, getOffset()) * HUNDREDTHS_MULTIPLIER;
}
@Override
public String toString()
{
CorrectedBinaryMessage sub = getMessage().getSubMessage(getOffset(), getOffset() + 87);
return "GEO-FENCE POSITION:" + getPosition() + " RADIUS:" + getRadius() + " KM";
return "CIRCLE 2D POSITION:" + getPosition() + " RADIUS:" + DECIMAL_FORMAT.format(getRadius()) + " MTRS";
}
}

View File

@@ -21,15 +21,16 @@ package io.github.dsheirer.module.decode.ip.lrrp.token;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import java.text.DecimalFormat;
/**
* LRRP 3D Position with latitude, longitude, altitude and radius
*/
public class GeoFencePosition3D extends GeoFencePosition
public class Circle3d extends Circle2d
{
private static final int[] ALTITUDE_WHOLE = new int[]{88, 89, 90, 91, 92, 93, 94, 95};
private static final int[] ALTITUDE_FRACTIONAL = new int[]{96, 97, 98, 99, 100, 101, 102, 103};
private static final int[] ALTITUDE_ACCURACY_WHOLE = new int[]{104, 105, 106, 107, 108, 109, 110, 111};
private static final int[] ALTITUDE_ACCURACY_FRACTIONAL = new int[]{112, 113, 114, 115, 116, 117, 118, 119};
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00");
private static final int[] ALTITUDE = new int[]{88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103};
private static final int[] ALTITUDE_ACCURACY = new int[]{104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119};
/**
* Constructs an instance of a 3D position token.
@@ -37,7 +38,7 @@ public class GeoFencePosition3D extends GeoFencePosition
* @param message containing the heading
* @param offset to the start of the token
*/
public GeoFencePosition3D(CorrectedBinaryMessage message, int offset)
public Circle3d(CorrectedBinaryMessage message, int offset)
{
super(message, offset);
}
@@ -45,7 +46,7 @@ public class GeoFencePosition3D extends GeoFencePosition
@Override
public TokenType getTokenType()
{
return TokenType.POSITION_GEO_FENCE_3D;
return TokenType.CIRCLE_3D;
}
/**
@@ -55,7 +56,7 @@ public class GeoFencePosition3D extends GeoFencePosition
*/
public float getAltitude()
{
return getFloat(ALTITUDE_WHOLE, ALTITUDE_FRACTIONAL);
return getMessage().getInt(ALTITUDE, getOffset()) * HUNDREDTHS_MULTIPLIER;
}
/**
@@ -64,7 +65,7 @@ public class GeoFencePosition3D extends GeoFencePosition
*/
public float getAltitudeAccuracy()
{
return getFloat(ALTITUDE_ACCURACY_WHOLE, ALTITUDE_ACCURACY_FRACTIONAL);
return getMessage().getInt(ALTITUDE_ACCURACY, getOffset()) * HUNDREDTHS_MULTIPLIER;
}
@@ -72,10 +73,10 @@ public class GeoFencePosition3D extends GeoFencePosition
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("GEO-FENCE POSITION:").append(getPosition());
sb.append(" RADIUS:").append(getRadius());
sb.append("KM ALTITUDE:").append(getAltitude());
sb.append(" ALT ACCURACY:").append(getAltitudeAccuracy());
sb.append("CIRCLE 3D POSITION:").append(getPosition());
sb.append(" RADIUS:").append(DECIMAL_FORMAT.format(getRadius()));
sb.append("MTRS ALTITUDE:").append(DECIMAL_FORMAT.format(getAltitude()));
sb.append(" ALT ACCURACY:").append(DECIMAL_FORMAT.format(getAltitudeAccuracy()));
return sb.toString();
}
}

View File

@@ -21,6 +21,8 @@ package io.github.dsheirer.module.decode.ip.lrrp.token;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import java.text.DecimalFormat;
/**
* LRRP Heading Token
*
@@ -29,8 +31,9 @@ import io.github.dsheirer.bits.CorrectedBinaryMessage;
*/
public class Heading extends Token
{
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("000.0");
private static final int[] HEADING = new int[]{8, 9, 10, 11, 12, 13, 14, 15};
private static final float HEADING_MULTIPLIER = 360.0f / 256.0f;
private static final float HEADING_MULTIPLIER = 2.0f;
/**
* Constructs an instance of a heading token.
@@ -60,6 +63,6 @@ public class Heading extends Token
@Override
public String toString()
{
return "HEADING:" + getHeading();
return "HEADING:" + DECIMAL_FORMAT.format(getHeading());
}
}

View File

@@ -21,24 +21,24 @@ package io.github.dsheirer.module.decode.ip.lrrp.token;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import java.text.DecimalFormat;
/**
* LRRP Position Token
*
* Start Token: 0x66
* Total Length: 9 bytes
*/
public class Position extends Token
public class Point2d extends Token
{
private static final int LATITUDE_HEMISPHERE_FLAG = 8;
private static final int[] LATITUDE = new int[]{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
private static final int[] LATITUDE = new int[]{8, 9, 10, 11, 12, 13, 14, 15, 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 LONGITUDE_HEMISPHERE_FLAG = 40;
private static final int[] LONGITUDE = new int[]{41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
private static final int[] LONGITUDE = new int[]{40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71};
private static final double LATITUDE_MULTIPLIER = 180.0 / 4294967295.0d;
private static final double LONGITUDE_MULTIPLIER = 360.0 / 4294967295.0d;
protected static final float FRACTIONAL_MULTIPLIER = 0.01f;
protected static final float HUNDREDTHS_MULTIPLIER = 0.01f;
private LRRPPosition mPosition;
@@ -48,7 +48,7 @@ public class Position extends Token
* @param message containing the heading
* @param offset to the start of the token
*/
public Position(CorrectedBinaryMessage message, int offset)
public Point2d(CorrectedBinaryMessage message, int offset)
{
super(message, offset);
}
@@ -56,7 +56,7 @@ public class Position extends Token
@Override
public TokenType getTokenType()
{
return TokenType.POSITION;
return TokenType.POINT_2D;
}
/**
@@ -77,7 +77,7 @@ public class Position extends Token
*/
public double getLatitude()
{
return getMessage().getInt(LATITUDE, getOffset()) * LATITUDE_MULTIPLIER * (getMessage().get(LATITUDE_HEMISPHERE_FLAG) ? -1 : 1);
return getMessage().getInt(LATITUDE, getOffset()) * LATITUDE_MULTIPLIER;// * (getMessage().get(LATITUDE_HEMISPHERE_FLAG) ? -1 : 1);
}
/**
@@ -85,7 +85,7 @@ public class Position extends Token
*/
public double getLongitude()
{
return getMessage().getInt(LONGITUDE, getOffset()) * LONGITUDE_MULTIPLIER * (getMessage().get(LONGITUDE_HEMISPHERE_FLAG) ? -1 : 1);
return getMessage().getInt(LONGITUDE, getOffset()) * LONGITUDE_MULTIPLIER;// * (getMessage().get(LONGITUDE_HEMISPHERE_FLAG) ? -1 : 1);
}
/**
@@ -97,12 +97,12 @@ public class Position extends Token
protected float getFloat(int[] whole, int[] fractional)
{
return getMessage().getInt(whole, getOffset()) +
(getMessage().getInt(fractional, getOffset()) * FRACTIONAL_MULTIPLIER);
(getMessage().getInt(fractional, getOffset()) * HUNDREDTHS_MULTIPLIER);
}
@Override
public String toString()
{
return "POSITION:" + getPosition();
return "POINT:" + getPosition();
}
}

View File

@@ -24,11 +24,10 @@ import io.github.dsheirer.bits.CorrectedBinaryMessage;
/**
* LRRP 3D Position with latitude, longitude and altitude
*/
public class Position3D extends Position
public class Point3d extends Point2d
{
//Note: these may not be correct ... there may be 3 bytes available for altitude
private static final int[] ALTITUDE_WHOLE = new int[]{72, 73, 74, 75, 76, 77, 78, 79};
private static final int[] ALTITUDE_FRACTIONAL = new int[]{80, 81, 82, 83, 84, 85, 86, 87};
private static final int[] ALTITUDE = new int[]{72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 91, 92, 93, 94, 95};
/**
* Constructs an instance of an approximate position token.
@@ -36,7 +35,7 @@ public class Position3D extends Position
* @param message containing the heading
* @param offset to the start of the token
*/
public Position3D(CorrectedBinaryMessage message, int offset)
public Point3d(CorrectedBinaryMessage message, int offset)
{
super(message, offset);
}
@@ -44,7 +43,7 @@ public class Position3D extends Position
@Override
public TokenType getTokenType()
{
return TokenType.POSITION_3D;
return TokenType.POINT_3D;
}
/**
@@ -54,13 +53,13 @@ public class Position3D extends Position
*/
public float getAltitude()
{
return getFloat(ALTITUDE_WHOLE, ALTITUDE_FRACTIONAL);
return getMessage().getInt(ALTITUDE, getOffset()) * HUNDREDTHS_MULTIPLIER;
}
@Override
public String toString()
{
CorrectedBinaryMessage sub = getMessage().getSubMessage(getOffset(), getOffset() + 87);
return "POSITION:" + getPosition() + " ALTITUDE:" + getAltitude() + " MTRS";
return "POINT:" + getPosition() + " ALTITUDE:" + getAltitude() + " MTRS";
}
}

View File

@@ -0,0 +1,60 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.ip.lrrp.token;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
/**
* LRRP Unknown Request Type 61
* <p>
* Total Length: 2 bytes
*/
public class Request61 extends Token
{
private static final int[] VALUE = new int[]{8, 9, 10, 11, 12, 13, 14, 15};
/**
* Constructs an instance of a heading token.
*
* @param message containing the heading
* @param offset to the start of the token
*/
public Request61(CorrectedBinaryMessage message, int offset)
{
super(message, offset);
}
@Override
public TokenType getTokenType()
{
return TokenType.REQUEST_61;
}
public int getValue()
{
return getMessage().getInt(VALUE, getOffset());
}
@Override
public String toString()
{
return "REQUEST-61:" + getValue();
}
}

View File

@@ -0,0 +1,60 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.ip.lrrp.token;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
/**
* LRRP Unknown Request Type 73
*
* Total Length: 2 bytes
*/
public class Request73 extends Token
{
private static final int[] VALUE = new int[]{8, 9, 10, 11, 12, 13, 14, 15};
/**
* Constructs an instance of a heading token.
*
* @param message containing the heading
* @param offset to the start of the token
*/
public Request73(CorrectedBinaryMessage message, int offset)
{
super(message, offset);
}
@Override
public TokenType getTokenType()
{
return TokenType.REQUEST_73;
}
public int getValue()
{
return getMessage().getInt(VALUE, getOffset());
}
@Override
public String toString()
{
return "REQUEST-73:" + getValue();
}
}

View File

@@ -0,0 +1,99 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.ip.lrrp.token;
import com.google.common.base.Joiner;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* LRRP Requested Element Token
*
* Start Token: various
* Total Length: 1 byte
*/
public class RequestedTokens extends Token
{
private List<TokenType> mRequestedTokens = new ArrayList<>();
private List<String> mUnrecognizedRequestedTokens = new ArrayList<>();
/**
* Constructs an instance of a heading token.
*/
public RequestedTokens()
{
super(null, 0);
}
@Override
public TokenType getTokenType()
{
return TokenType.REQUESTED_TOKENS;
}
/**
* Adds the recognized requested token type
*/
public void add(TokenType tokenType)
{
mRequestedTokens.add(tokenType);
}
public void add(String unrecognizedTokenType)
{
mUnrecognizedRequestedTokens.add(unrecognizedTokenType);
Collections.sort(mUnrecognizedRequestedTokens);
}
/**
* Indicates if this object has requested tokens.
*/
public boolean hasRequestedTokens()
{
return !mRequestedTokens.isEmpty();
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("REQUESTED TOKENS [");
if(!mRequestedTokens.isEmpty())
{
sb.append(Joiner.on(",").join(mRequestedTokens));
}
if(!mRequestedTokens.isEmpty() && !mUnrecognizedRequestedTokens.isEmpty())
{
sb.append(",");
}
if(!mUnrecognizedRequestedTokens.isEmpty())
{
sb.append("UNRECOGNIZED(").append(Joiner.on(",").join(mUnrecognizedRequestedTokens)).append(")");
}
sb.append("]");
return sb.toString();
}
}

View File

@@ -29,9 +29,9 @@ import io.github.dsheirer.bits.CorrectedBinaryMessage;
*/
public class Response extends Token
{
private static final int CODE_LENGTH_FLAG = 16;
private static final int[] ONE_BYTE_CODE = new int[]{17, 18, 19, 20, 21, 22, 23};
private static final int[] TWO_BYTE_CODE = new int[]{17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
private static final int CODE_LENGTH_FLAG = 8;
private static final int[] ONE_BYTE_CODE = new int[]{9, 10, 11, 12, 13, 14, 15};
private static final int[] TWO_BYTE_CODE = new int[]{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
/**
* Constructs an instance of a response code token.
@@ -65,11 +65,11 @@ public class Response extends Token
{
if(isExtendedCode())
{
return getMessage().getInt(TWO_BYTE_CODE);
return getMessage().getInt(TWO_BYTE_CODE, getOffset());
}
else
{
return getMessage().getInt(ONE_BYTE_CODE);
return getMessage().getInt(ONE_BYTE_CODE, getOffset());
}
}
@@ -94,9 +94,9 @@ public class Response extends Token
if(responseCode == ResponseCode.UNKNOWN)
{
return "RESPONSE CODE: UNKNOWN[" + getCodeValue() + "]";
return "RESPONSE: UNKNOWN[" + getCodeValue() + "]";
}
return "RESPONSE CODE:" + responseCode;
return "RESPONSE:" + responseCode;
}
}

View File

@@ -28,7 +28,9 @@ public enum ResponseCode
{
SUCCESS(0x0, "SUCCESS"),
INVALID_COMMAND(0x0A, "INVALID COMMAND"),
UNKNOWN_ERROR_F(0x0F, "UNRECOGNIZED ERROR [0F]"),
NO_GPS(0x10, "NO GPS"),
DUPLICATE_REQUEST(0x16, "DUPLICATE REQUEST"),
GPS_INITIALIZING(0x200, "GPS INITIALIZING"),
UNKNOWN(-1, "UNKNOWN");

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2021 Dennis Sheirer
*
* This 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,16 +21,19 @@ package io.github.dsheirer.module.decode.ip.lrrp.token;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import java.text.DecimalFormat;
/**
* LRRP Speed Token
*
* <p>
* Start Token: 0x6C
* Total Length: 3 bytes
*/
public class Speed extends Token
{
private static final int[] UNKNOWN = new int[]{8, 9, 10, 11, 12, 13, 14, 15};
private static final int[] SPEED = new int[]{16, 17, 18, 19, 20, 21, 22, 23};
private static final int[] SPEED = new int[]{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
private static final double SPEED_MULTIPLIER = 0.01; //Units of 1/100 mph
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00");
/**
* Constructs an instance of a heading token.
@@ -52,14 +55,14 @@ public class Speed extends Token
/**
* Speed in kilometers per hour (kph)
*/
public long getSpeed()
public double getSpeed()
{
return getMessage().getInt(SPEED, getOffset());
return getMessage().getInt(SPEED, getOffset()) * SPEED_MULTIPLIER;
}
@Override
public String toString()
{
return "SPEED:" + getSpeed() + " KPH";
return "SPEED:" + DECIMAL_FORMAT.format(getSpeed()) + " MPH";
}
}

View File

@@ -0,0 +1,54 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.ip.lrrp.token;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
/**
* LRRP Success Token
*
* Start Token: 0x38
* Total Length: 1 bytes
*/
public class Success extends Token
{
/**
* Constructs an instance of a heading token.
*
* @param message containing the heading
* @param offset to the start of the token
*/
public Success(CorrectedBinaryMessage message, int offset)
{
super(message, offset);
}
@Override
public TokenType getTokenType()
{
return TokenType.SUCCESS;
}
@Override
public String toString()
{
return "SUCCESS!";
}
}

View File

@@ -36,24 +36,38 @@ public class TokenFactory
return new Heading(message, offset);
case IDENTITY:
return new Identity(message, offset);
case POSITION:
return new Position(message, offset);
case POSITION_GEO_FENCE:
return new GeoFencePosition(message, offset);
case POSITION_3D:
return new Position3D(message, offset);
case POSITION_GEO_FENCE_3D:
return new GeoFencePosition3D(message, offset);
case POINT_2D:
return new Point2d(message, offset);
case CIRCLE_2D:
return new Circle2d(message, offset);
case POINT_3D:
return new Point3d(message, offset);
case CIRCLE_3D:
return new Circle3d(message, offset);
case RESPONSE:
return new Response(message, offset);
case SPEED:
return new Speed(message, offset);
case SUCCESS:
return new Success(message, offset);
case TIMESTAMP:
return new Timestamp(message, offset);
case TRIGGER_DISTANCE:
return new TriggerDistance(message, offset);
case TRIGGER_GPIO:
return new TriggerGpio(message, offset);
case TRIGGER_ON_MOVE:
return new TriggerOnMove(message, offset);
case TRIGGER_PERIODIC:
return new TriggerPeriodic(message, offset);
case VERSION:
return new Version(message, offset);
case UNKNOWN_23:
return new Unknown23(message, offset);
case REQUEST_61:
return new Request61(message, offset);
case REQUEST_73:
return new Request73(message, offset);
case UNKNOWN:
default:
return new UnknownToken(message, offset, remainingCharacterCount);

View File

@@ -19,6 +19,7 @@
package io.github.dsheirer.module.decode.ip.lrrp.token;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
@@ -30,32 +31,54 @@ import java.util.Map;
*/
public enum TokenType
{
IDENTITY("22", -1),
UNKNOWN_23("23", 1),
TIMESTAMP("34", 5),
VERSION("36", 1),
RESPONSE("37", -1),
// SUCCESS_RESPONSE_CODE( "38", 0), //Maybe: https://github.com/pboyd04/Moto.Net/blob/master/Moto.Net/Mototrbo/LRRP/TriggeredLocationStartResponsePacket.cs
POSITION_GEO_FENCE("51", 10),
POSITION_GEO_FENCE_3D("55", 15),
HEADING("56", 1),
POSITION("66", 8),
POSITION_3D("69", 11),
SPEED("6C", 2),
UNKNOWN("0",0);
IDENTITY("22", -1, "IDENTITY"),
UNKNOWN_23("23", 1, "UNKNOWN 23"),
TRIGGER_PERIODIC("31", 1, "TRIGGER PERIODIC"),
TIMESTAMP("34", 5, "TIMESTAMP"),
VERSION("36", 1, "VERSION"),
RESPONSE("37", -1, "RESPONSE"),
SUCCESS( "38", 0, "SUCCESS"),
REQUEST_3A("3A", 0,"REQUEST-3A"),
TRIGGER_GPIO("42", 0, "TRIGGER GPIO"),
TRIGGER_DISTANCE("4A", 1, "TRIGGER DISTANCE"), //Guess - not sure
ALTITUDE_ACCURACY("50", 0,"ALTITUDE ACCURACY"),
CIRCLE_2D("51", 10, "CIRCLE 2D"),
TIME("52", 0,"TIME"),
ALTITUDE("54", 0,"ALTITUDE"),
CIRCLE_3D("55", 15, "CIRCLE 3D"),
HEADING("56", 1, "HEADING"),
HORIZONTAL_DIRECTION("57", 0,"HORIZONTAL DIRECTION"),
REQUEST_61("61", 1, "REQUEST-61"),
REQUEST_62("62", 0,"REQUEST-62"),
REQUEST_64("64", 0,"REQUEST-64"),
POINT_2D("66", 8, "POINT 2D"),
POINT_3D("69", 11, "POINT 3D"),
SPEED("6C", 2, "SPEED"),
REQUEST_73("73", 1, "REQUEST-73"),
TRIGGER_ON_MOVE("78", 1, "TRIGGER ON MOVE"),
REQUESTED_TOKENS("000", 0, "REQUESTED TOKENS"),
UNKNOWN("0",0, "UNKNOWN");
private String mValue;
private int mLength;
private String mLabel;
/**
* Tokens that have parameters in request packet messages
*/
private static EnumSet<TokenType> REQUEST_PARAMETER_TOKENS = EnumSet.of(IDENTITY, TRIGGER_DISTANCE, TRIGGER_GPIO,
TRIGGER_ON_MOVE, TRIGGER_PERIODIC, REQUEST_61, REQUEST_73);
/**
* Constructs an instance
* @param value of the token
* @param length of the token, exclusive of the identifier, where -1 indicates a variable length token.
*/
TokenType(String value, int length)
TokenType(String value, int length, String label)
{
mValue = value;
mLength = length;
mLabel = label;
}
/**
@@ -83,6 +106,15 @@ public enum TokenType
return mLength;
}
/**
* Indicates if this is a request type token that has an optional parameter (e.g. the trigger tokens).
*/
public boolean isRequestParameterToken()
{
return REQUEST_PARAMETER_TOKENS.contains(this);
}
private static final Map<String,TokenType> LOOKUP_MAP = new HashMap<>();
static
@@ -107,4 +139,10 @@ public enum TokenType
return UNKNOWN;
}
@Override
public String toString()
{
return mLabel;
}
}

View File

@@ -0,0 +1,65 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.ip.lrrp.token;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
import java.text.DecimalFormat;
/**
* LRRP Trigger Distance Token
*
* Total Length: 2 bytes
*/
public class TriggerDistance extends Token
{
private static final int[] DISTANCE = new int[]{8, 9, 10, 11, 12, 13, 14, 15};
/**
* Constructs an instance of a heading token.
*
* @param message containing the heading
* @param offset to the start of the token
*/
public TriggerDistance(CorrectedBinaryMessage message, int offset)
{
super(message, offset);
}
@Override
public TokenType getTokenType()
{
return TokenType.TRIGGER_DISTANCE;
}
/**
* Distance for trigger
*/
public int getDistance()
{
return getMessage().getInt(DISTANCE, getOffset());
}
@Override
public String toString()
{
return "TRIGGER DISTANCE:" + getDistance();
}
}

View File

@@ -0,0 +1,53 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.ip.lrrp.token;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
/**
* LRRP Trigger on GPIO Token
*
* Total Length: 1 byte
*/
public class TriggerGpio extends Token
{
/**
* Constructs an instance of a heading token.
*
* @param message containing the heading
* @param offset to the start of the token
*/
public TriggerGpio(CorrectedBinaryMessage message, int offset)
{
super(message, offset);
}
@Override
public TokenType getTokenType()
{
return TokenType.TRIGGER_GPIO;
}
@Override
public String toString()
{
return "TRIGGER ON GPIO";
}
}

View File

@@ -0,0 +1,53 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.ip.lrrp.token;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
/**
* LRRP Trigger on Move Token
*
* Total Length: 1 byte
*/
public class TriggerOnMove extends Token
{
/**
* Constructs an instance of a heading token.
*
* @param message containing the heading
* @param offset to the start of the token
*/
public TriggerOnMove(CorrectedBinaryMessage message, int offset)
{
super(message, offset);
}
@Override
public TokenType getTokenType()
{
return TokenType.TRIGGER_ON_MOVE;
}
@Override
public String toString()
{
return "TRIGGER ON MOVE";
}
}

View File

@@ -0,0 +1,63 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.ip.lrrp.token;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
/**
* LRRP Trigger Periodic Token
*
* Total Length: 2 bytes
*/
public class TriggerPeriodic extends Token
{
private static final int[] SECONDS = new int[]{8, 9, 10, 11, 12, 13, 14, 15};
/**
* Constructs an instance of a heading token.
*
* @param message containing the heading
* @param offset to the start of the token
*/
public TriggerPeriodic(CorrectedBinaryMessage message, int offset)
{
super(message, offset);
}
@Override
public TokenType getTokenType()
{
return TokenType.TRIGGER_DISTANCE;
}
/**
* Seconds for trigger
*/
public int getSeconds()
{
return getMessage().getInt(SECONDS, getOffset());
}
@Override
public String toString()
{
return "TRIGGER EVERY:" + getSeconds() + " SECS";
}
}

View File

@@ -36,11 +36,16 @@ import io.github.dsheirer.message.StuffBitsMessage;
import io.github.dsheirer.message.SyncLossMessage;
import io.github.dsheirer.module.ProcessingChain;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.ip.IPacket;
import io.github.dsheirer.module.decode.ip.ipv4.IPV4Packet;
import io.github.dsheirer.module.decode.ip.lrrp.LRRPPacket;
import io.github.dsheirer.module.decode.ip.udp.UDPPacket;
import io.github.dsheirer.module.decode.p25.audio.P25P1AudioModule;
import io.github.dsheirer.module.decode.p25.phase1.message.P25Message;
import io.github.dsheirer.module.decode.p25.phase1.message.P25MessageFactory;
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUMessageFactory;
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.PDUSequence;
import io.github.dsheirer.module.decode.p25.phase1.message.pdu.packet.PacketMessage;
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;
@@ -58,6 +63,7 @@ import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.function.Consumer;
/**
@@ -446,7 +452,7 @@ public class P25P1MessageFramer implements Listener<Dibit>, IP25P1DataUnitDetect
public static void main(String[] args)
{
Path directory = Paths.get("/home/denny/SDRTrunk/recordings/LRRP P25");
Path directory = Paths.get("/home/denny/Documents/TMR/APCO25/GPS/bkmzk007");
// Path directory = Paths.get("/media/denny/500G1EXT4/PBITRecordings");
UserPreferences userPreferences = new UserPreferences();
@@ -468,6 +474,7 @@ public class P25P1MessageFramer implements Listener<Dibit>, IP25P1DataUnitDetect
mLog.info("Processing Directory: " + directory.toString());
try(OutputStream logOutput = Files.newOutputStream(directory.resolve("log.txt")))
{
try
@@ -504,6 +511,22 @@ public class P25P1MessageFramer implements Listener<Dibit>, IP25P1DataUnitDetect
{
logOutput.write(message.toString().getBytes());
logOutput.write("\n".getBytes());
if(message instanceof PacketMessage packet)
{
if(packet.getPacket() instanceof IPV4Packet ipv4)
{
if(ipv4.getPayload() instanceof UDPPacket udp)
{
if(udp.getPayload() instanceof LRRPPacket lrrp)
{
logOutput.write("\n".getBytes());
logOutput.write(lrrp.getMessage().toHexString().getBytes());
logOutput.write("\n\n".getBytes());
}
}
}
}
}
catch(IOException ioe)
{

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.module.decode.p25.phase1.message.tsbk;
@@ -171,7 +168,7 @@ public enum Opcode
MOTOROLA_OSP_PATCH_GROUP_DELETE(1, "PATCH GROUP DELE", "MOTOROLA PATCH GROUP DELETE"),
MOTOROLA_OSP_PATCH_GROUP_CHANNEL_GRANT(2, "PTCH GRP VCHN GR", "MOTOROLA PATCH GROUP CHANNEL GRANT"),
MOTOROLA_OSP_PATCH_GROUP_CHANNEL_GRANT_UPDATE(3, "PTCH GRP VCH UPD", "MOTOROLA PATCH GROUP CHANNEL GRANT UPDATE"),
MOTOROLA_OSP_TRAFFIC_CHANNEL_ID(5, "TRAFFIC CHANNEL", "TRAFFIC CHANNEL"),
MOTOROLA_OSP_TRAFFIC_CHANNEL_ID(5, "TRAFFIC CHANNEL", "MOTOROLA TRAFFIC CHANNEL"),
MOTOROLA_OSP_DENY_RESPONSE(7, "DENY RESPONSE", "MOTOROLA DENY RESPONSE"),
MOTOROLA_OSP_SYSTEM_LOADING(9, "SYSTEM LOADING", "SYSTEM LOADING"),
MOTOROLA_OSP_BASE_STATION_ID(11, "CCH BASE STAT ID", "CONTROL CHANNEL BASE STATION ID"),

View File

@@ -22,8 +22,7 @@ package io.github.dsheirer.util;
import io.github.dsheirer.module.decode.ip.IPacket;
import io.github.dsheirer.module.decode.ip.ipv4.IPV4Packet;
import io.github.dsheirer.module.decode.ip.lrrp.LRRPPacket;
import io.github.dsheirer.module.decode.ip.lrrp.token.GeoFencePosition;
import io.github.dsheirer.module.decode.ip.lrrp.token.Position;
import io.github.dsheirer.module.decode.ip.lrrp.token.Point2d;
import io.github.dsheirer.module.decode.ip.lrrp.token.Token;
import io.github.dsheirer.module.decode.ip.udp.UDPPacket;
import org.jdesktop.swingx.mapviewer.GeoPosition;
@@ -72,10 +71,10 @@ public class PacketUtil
for(Token token : lrrpPacket.getTokens())
{
if(token instanceof Position)
if(token instanceof Point2d)
{
Position position = (Position) token;
return new GeoPosition(position.getLatitude(), position.getLongitude());
Point2d point2d = (Point2d) token;
return new GeoPosition(point2d.getLatitude(), point2d.getLongitude());
}
}
}