mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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!";
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user