diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/LRRPHeader.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/LRRPHeader.java index 0b5b8c29..55fd288b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/LRRPHeader.java +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/LRRPHeader.java @@ -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 @@ -53,6 +53,22 @@ public class LRRPHeader extends Header setValid(getMessage().size() >= (getOffset() + getLength() + getPayloadLength())); } + /** + * Integer value of the LRRP Packet type + */ + public int getLrrpPacketTypeValue() + { + return getMessage().getInt(TYPE, getOffset()); + } + + /** + * LRRP Packet Type + */ + public LRRPPacketType getLRRPPacketType() + { + return LRRPPacketType.fromValue(getLrrpPacketTypeValue()); + } + /** * Length of the payload in 8-bit characters * diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/LRRPPacket.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/LRRPPacket.java index 8cdd3686..d0c1aaab 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/LRRPPacket.java +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/LRRPPacket.java @@ -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 @@ -56,7 +56,16 @@ public class LRRPPacket extends Packet public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("LRRP"); + LRRPPacketType type = getHeader().getLRRPPacketType(); + + if(type == LRRPPacketType.UNKNOWN) + { + sb.append("LRRP TYPE:UNKNOWN [").append(getHeader().getLrrpPacketTypeValue()).append("]"); + } + else + { + sb.append("LRRP ").append(type); + } for(Token token: getTokens()) { @@ -100,7 +109,6 @@ public class LRRPPacket extends Packet String tokenId = getTokenIdentifier(offset); Token token = TokenFactory.createToken(tokenId, getMessage(), offset, characterCount); mTokens.add(token); - int length = token.getByteLength(); characterCount -= token.getByteLength(); offset += (8 * token.getByteLength()); } diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/LRRPPacketType.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/LRRPPacketType.java new file mode 100644 index 00000000..fd1e8dfc --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/LRRPPacketType.java @@ -0,0 +1,79 @@ +/* + * ***************************************************************************** + * 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 + * **************************************************************************** + */ + +package io.github.dsheirer.module.decode.ip.lrrp; + +/** + * LRRP Packet Type enumeration + */ +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"), + + UNKNOWN(-1, "UNKNOWN"); + + private int mValue; + private String mLabel; + + LRRPPacketType(int value, String label) + { + mValue = value; + mLabel = label; + } + + /** + * Numeric value of the type. + */ + public int getValue() + { + return mValue; + } + + @Override + public String toString() + { + return mLabel; + } + + /** + * Lookup the LRRP packet type from the value. + * @param value to lookup + * @return entry or UNKNOWN + */ + public static LRRPPacketType fromValue(int value) + { + for(LRRPPacketType lrrpPacketType: LRRPPacketType.values()) + { + if(lrrpPacketType.getValue() == value) + { + return lrrpPacketType; + } + } + + return UNKNOWN; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/GeoFencePosition.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/GeoFencePosition.java new file mode 100644 index 00000000..c2fa043a --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/GeoFencePosition.java @@ -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 + * **************************************************************************** + */ + +package io.github.dsheirer.module.decode.ip.lrrp.token; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; + +/** + * LRRP Geo-Fence Position with latitude, longitude and radius + */ +public class GeoFencePosition extends Position +{ + 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}; + + /** + * Constructs an instance of an approximate position token. + * + * @param message containing the heading + * @param offset to the start of the token + */ + public GeoFencePosition(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + @Override + public TokenType getTokenType() + { + return TokenType.POSITION_GEO_FENCE; + } + + /** + * Radius of position + * + * @return radius in meters + */ + public float getRadius() + { + return getFloat(RADIUS_WHOLE, RADIUS_FRACTIONAL); + } + + @Override + public String toString() + { + CorrectedBinaryMessage sub = getMessage().getSubMessage(getOffset(), getOffset() + 87); + return "GEO-FENCE POSITION:" + getPosition() + " RADIUS:" + getRadius() + " KM"; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/GeoFencePosition3D.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/GeoFencePosition3D.java new file mode 100644 index 00000000..1a0f905a --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/GeoFencePosition3D.java @@ -0,0 +1,81 @@ +/* + * ***************************************************************************** + * 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 + * **************************************************************************** + */ + +package io.github.dsheirer.module.decode.ip.lrrp.token; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; + +/** + * LRRP 3D Position with latitude, longitude, altitude and radius + */ +public class GeoFencePosition3D extends GeoFencePosition +{ + 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}; + + /** + * Constructs an instance of a 3D position token. + * + * @param message containing the heading + * @param offset to the start of the token + */ + public GeoFencePosition3D(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + @Override + public TokenType getTokenType() + { + return TokenType.POSITION_GEO_FENCE_3D; + } + + /** + * Altitude + * + * @return altitude in meters + */ + public float getAltitude() + { + return getFloat(ALTITUDE_WHOLE, ALTITUDE_FRACTIONAL); + } + + /** + * Altitude accuracy + * @return accuracy in meters + */ + public float getAltitudeAccuracy() + { + return getFloat(ALTITUDE_ACCURACY_WHOLE, ALTITUDE_ACCURACY_FRACTIONAL); + } + + + @Override + 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()); + return sb.toString(); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Heading.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Heading.java index 807b0512..72b8e91c 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Heading.java +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Heading.java @@ -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 @@ -30,6 +30,7 @@ import io.github.dsheirer.bits.CorrectedBinaryMessage; public class Heading extends Token { 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; /** * Constructs an instance of a heading token. @@ -51,9 +52,9 @@ public class Heading extends Token /** * Heading degrees relative to true North */ - public long getHeading() + public float getHeading() { - return getMessage().getInt(HEADING, getOffset()); + return getMessage().getInt(HEADING, getOffset()) * HEADING_MULTIPLIER; } @Override diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Position.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Position.java index 0fd65a25..4f7018f9 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Position.java +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Position.java @@ -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 @@ -29,18 +29,21 @@ import io.github.dsheirer.bits.CorrectedBinaryMessage; */ public class Position extends Token { - private static final int[] LATITUDE = new int[]{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 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, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; - private static final int[] LONGITUDE = new int[]{40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 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, 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; private LRRPPosition mPosition; /** - * Constructs an instance of a heading token. + * Constructs an instance of a position token. * * @param message containing the heading * @param offset to the start of the token @@ -74,7 +77,7 @@ public class Position extends Token */ public double getLatitude() { - return getMessage().getInt(LATITUDE, getOffset()) * LATITUDE_MULTIPLIER; + return getMessage().getInt(LATITUDE, getOffset()) * LATITUDE_MULTIPLIER * (getMessage().get(LATITUDE_HEMISPHERE_FLAG) ? -1 : 1); } /** @@ -82,7 +85,19 @@ public class Position extends Token */ public double getLongitude() { - return getMessage().getInt(LONGITUDE, getOffset()) * LONGITUDE_MULTIPLIER; + return getMessage().getInt(LONGITUDE, getOffset()) * LONGITUDE_MULTIPLIER * (getMessage().get(LONGITUDE_HEMISPHERE_FLAG) ? -1 : 1); + } + + /** + * Calculates the floating point value specified by the message index arrays. + * @param whole units indexes + * @param fractional one-hundredth units indexes + * @return full value + */ + protected float getFloat(int[] whole, int[] fractional) + { + return getMessage().getInt(whole, getOffset()) + + (getMessage().getInt(fractional, getOffset()) * FRACTIONAL_MULTIPLIER); } @Override diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Position3D.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Position3D.java index d347ca0f..667cc521 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Position3D.java +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Position3D.java @@ -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 @@ -22,14 +22,16 @@ package io.github.dsheirer.module.decode.ip.lrrp.token; import io.github.dsheirer.bits.CorrectedBinaryMessage; /** - * LRRP 3-D Position with latitude, longitude and altitude + * LRRP 3D Position with latitude, longitude and altitude */ public class Position3D extends Position { - private static final int[] ALTITUDE = new int[]{72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87}; + //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}; /** - * Constructs an instance of a heading token. + * Constructs an instance of an approximate position token. * * @param message containing the heading * @param offset to the start of the token @@ -50,15 +52,15 @@ public class Position3D extends Position * * @return altitude in meters */ - public int getAltitude() + public float getAltitude() { - return getMessage().getInt(ALTITUDE, getOffset()); + return getFloat(ALTITUDE_WHOLE, ALTITUDE_FRACTIONAL); } - @Override public String toString() { - return "POSITION:" + getPosition() + " ALT:" + getAltitude() + " MTRS"; + CorrectedBinaryMessage sub = getMessage().getSubMessage(getOffset(), getOffset() + 87); + return "POSITION:" + getPosition() + " ALTITUDE:" + getAltitude() + " MTRS"; } } diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Response.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Response.java new file mode 100644 index 00000000..2d37aa02 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Response.java @@ -0,0 +1,102 @@ +/* + * ***************************************************************************** + * 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 + * **************************************************************************** + */ + +package io.github.dsheirer.module.decode.ip.lrrp.token; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; + +/** + * LRRP Response Code Token + *

+ * Start Token: 0x37 + * Total Length: 2 or 3 bytes + */ +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}; + + /** + * Constructs an instance of a response code token. + * + * @param message containing the heading + * @param offset to the start of the token + */ + public Response(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + @Override + public TokenType getTokenType() + { + return TokenType.RESPONSE; + } + + /** + * Indicates if this is an extended (ie 2-byte) code. + */ + private boolean isExtendedCode() + { + return getMessage().get(CODE_LENGTH_FLAG); + } + + /** + * Response code. This value is either one byte or two bytes long. + */ + public int getCodeValue() + { + if(isExtendedCode()) + { + return getMessage().getInt(TWO_BYTE_CODE); + } + else + { + return getMessage().getInt(ONE_BYTE_CODE); + } + } + + /** + * Response code + */ + public ResponseCode getResponseCode() + { + return ResponseCode.fromValue(getCodeValue()); + } + + @Override + public int getByteLength() + { + return isExtendedCode() ? 3 : 2; + } + + @Override + public String toString() + { + ResponseCode responseCode = getResponseCode(); + + if(responseCode == ResponseCode.UNKNOWN) + { + return "RESPONSE CODE: UNKNOWN[" + getCodeValue() + "]"; + } + + return "RESPONSE CODE:" + responseCode; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/ResponseCode.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/ResponseCode.java new file mode 100644 index 00000000..0a5640bd --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/ResponseCode.java @@ -0,0 +1,80 @@ +/* + * ***************************************************************************** + * 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 + * **************************************************************************** + */ + +package io.github.dsheirer.module.decode.ip.lrrp.token; + +/** + * LRRP Response codes. + * + * From: https://github.com/pboyd04/Moto.Net/blob/master/Moto.Net/Mototrbo/LRRP/LRRPResponseCodes.cs + */ +public enum ResponseCode +{ + SUCCESS(0x0, "SUCCESS"), + INVALID_COMMAND(0x0A, "INVALID COMMAND"), + NO_GPS(0x10, "NO GPS"), + GPS_INITIALIZING(0x200, "GPS INITIALIZING"), + UNKNOWN(-1, "UNKNOWN"); + + private int mValue; + private String mLabel; + + /** + * Constructs an instance + * @param value of the code + * @param label for pretty printing + */ + ResponseCode(int value, String label) + { + mValue = value; + mLabel = label; + } + + /** + * Numeric value of the response code + */ + public int getValue() + { + return mValue; + } + + /** + * Lookup a response code from a value + * @param value to lookup + * @return matching response code or UNKNOWN + */ + public static ResponseCode fromValue(int value) + { + for(ResponseCode responseCode: ResponseCode.values()) + { + if(responseCode.getValue() == value) + { + return responseCode; + } + } + + return UNKNOWN; + } + + @Override + public String toString() + { + return mLabel; + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/TokenFactory.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/TokenFactory.java index f199c755..d85904f1 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/TokenFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/TokenFactory.java @@ -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 @@ -34,16 +34,24 @@ public class TokenFactory { case HEADING: 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 RESPONSE: + return new Response(message, offset); case SPEED: return new Speed(message, offset); case TIMESTAMP: return new Timestamp(message, offset); - case IDENTITY: - return new Identity(message, offset); + case VERSION: + return new Version(message, offset); case UNKNOWN_23: return new Unknown23(message, offset); case UNKNOWN: diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/TokenType.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/TokenType.java index b9dbe389..63d22ef6 100644 --- a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/TokenType.java +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/TokenType.java @@ -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 @@ -30,13 +30,18 @@ import java.util.Map; */ public enum TokenType { - POSITION("66", 8), - POSITION_3D("51", 10), - HEADING("56", 1), - SPEED("6C", 2), - TIMESTAMP("34", 5), 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); private String mValue; diff --git a/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Version.java b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Version.java new file mode 100644 index 00000000..af65ec06 --- /dev/null +++ b/src/main/java/io/github/dsheirer/module/decode/ip/lrrp/token/Version.java @@ -0,0 +1,61 @@ +/* + * ***************************************************************************** + * 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 + * **************************************************************************** + */ + +package io.github.dsheirer.module.decode.ip.lrrp.token; + +import io.github.dsheirer.bits.CorrectedBinaryMessage; + +/** + * LRRP Version Token + */ +public class Version extends Token +{ + private static final int[] VERSION = 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 Version(CorrectedBinaryMessage message, int offset) + { + super(message, offset); + } + + @Override + public TokenType getTokenType() + { + return TokenType.VERSION; + } + + /** + * LRRP Version + */ + public int getVersion() + { + return getMessage().getInt(VERSION, getOffset()); + } + + @Override + public String toString() + { + return "VERSION:" + getVersion(); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderState.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderState.java index bd1b5941..2d57bf20 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderState.java @@ -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 - * * ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * **************************************************************************** */ package io.github.dsheirer.module.decode.p25.phase1; @@ -41,10 +38,12 @@ import io.github.dsheirer.message.IMessage; import io.github.dsheirer.module.decode.DecoderType; import io.github.dsheirer.module.decode.event.DecodeEvent; import io.github.dsheirer.module.decode.event.DecodeEventType; +import io.github.dsheirer.module.decode.event.PlottableDecodeEvent; import io.github.dsheirer.module.decode.ip.IPacket; import io.github.dsheirer.module.decode.ip.ars.ARSPacket; import io.github.dsheirer.module.decode.ip.cellocator.MCGPPacket; 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.P25DecodeEvent; import io.github.dsheirer.module.decode.p25.P25TrafficChannelManager; @@ -134,7 +133,10 @@ import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.Uni import io.github.dsheirer.module.decode.p25.phase1.message.tsbk.standard.osp.UnitToUnitVoiceChannelGrantUpdate; import io.github.dsheirer.module.decode.p25.reference.Encryption; import io.github.dsheirer.module.decode.p25.reference.ServiceOptions; +import io.github.dsheirer.protocol.Protocol; import io.github.dsheirer.sample.Listener; +import io.github.dsheirer.util.PacketUtil; +import org.jdesktop.swingx.mapviewer.GeoPosition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -974,6 +976,35 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList broadcast(cellocatorEvent); } + else if(udpPayload instanceof LRRPPacket lrrpPacket) + { + MutableIdentifierCollection ic = new MutableIdentifierCollection(packet.getIdentifiers()); + + DecodeEvent lrrpEvent = P25DecodeEvent.builder(message.getTimestamp()) + .channel(getCurrentChannel()) + .details(lrrpPacket + " " + ipv4) + .eventDescription("LRRP") + .identifiers(ic) + .protocol(Protocol.LRRP) + .build(); + + broadcast(lrrpEvent); + + GeoPosition geoPosition = PacketUtil.extractGeoPosition(lrrpPacket); + + if (geoPosition != null) + { + PlottableDecodeEvent plottableDecodeEvent = PlottableDecodeEvent.plottableBuilder(message.getTimestamp()) + .channel(getCurrentChannel()) + .eventDescription(DecodeEventType.GPS.toString()) + .identifiers(ic) + .protocol(Protocol.LRRP) + .location(geoPosition) + .build(); + + broadcast(plottableDecodeEvent); + } + } else { MutableIdentifierCollection ic = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageFramer.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageFramer.java index d88f488d..f99b0781 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageFramer.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1MessageFramer.java @@ -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 - * * ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * **************************************************************************** */ package io.github.dsheirer.module.decode.p25.phase1; @@ -449,7 +446,7 @@ public class P25P1MessageFramer implements Listener, IP25P1DataUnitDetect public static void main(String[] args) { - Path directory = Paths.get("/media/denny/500G1EXT4/RadioRecordings/APCO25/Ken Noffsinger"); + Path directory = Paths.get("/home/denny/SDRTrunk/recordings/LRRP P25"); // Path directory = Paths.get("/media/denny/500G1EXT4/PBITRecordings"); UserPreferences userPreferences = new UserPreferences(); diff --git a/src/main/java/io/github/dsheirer/util/PacketUtil.java b/src/main/java/io/github/dsheirer/util/PacketUtil.java index 85696dee..1f8dd6b4 100644 --- a/src/main/java/io/github/dsheirer/util/PacketUtil.java +++ b/src/main/java/io/github/dsheirer/util/PacketUtil.java @@ -1,19 +1,51 @@ +/* + * ***************************************************************************** + * 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 + * **************************************************************************** + */ + 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.Token; import io.github.dsheirer.module.decode.ip.udp.UDPPacket; import org.jdesktop.swingx.mapviewer.GeoPosition; -public class PacketUtil { - public static GeoPosition extractGeoPosition(IPacket packet) { - if (packet instanceof IPV4Packet) { +/** + * Packet utility methods. + */ +public class PacketUtil +{ + /** + * Extracts a plottable position from a packet. + * @param packet to inspect and process + * @return geo position + */ + public static GeoPosition extractGeoPosition(IPacket packet) + { + if(packet instanceof IPV4Packet) + { IPV4Packet ipPacket = (IPV4Packet) packet; - if (ipPacket.getPayload() instanceof UDPPacket) { + if(ipPacket.getPayload() instanceof UDPPacket) + { UDPPacket udpPacket = (UDPPacket) ipPacket.getPayload(); return extractGeoPosition(udpPacket); } @@ -21,10 +53,12 @@ public class PacketUtil { return null; } - if (packet instanceof UDPPacket) { + if(packet instanceof UDPPacket) + { UDPPacket udpPacket = (UDPPacket) packet; - if (udpPacket.getPayload() instanceof LRRPPacket) { + if(udpPacket.getPayload() instanceof LRRPPacket) + { LRRPPacket lrrpPacket = (LRRPPacket) udpPacket.getPayload(); return extractGeoPosition(lrrpPacket); } @@ -32,12 +66,14 @@ public class PacketUtil { return null; } - if (packet instanceof LRRPPacket) { + if(packet instanceof LRRPPacket) + { LRRPPacket lrrpPacket = (LRRPPacket) packet; - for (Token token: lrrpPacket.getTokens()) + for(Token token : lrrpPacket.getTokens()) { - if (token instanceof Position) { + if(token instanceof Position) + { Position position = (Position) token; return new GeoPosition(position.getLatitude(), position.getLongitude()); }