492 Formatted Talkgroup and TalkgroupRange Editors (#493)

* Updates Talkgroup and Talkgroup ranges and editors to support formatted
talkgroup values.

* Updates talkgroup format masks to allow spaces (ie incomplete values)
 in talkgroup values.
This commit is contained in:
Denny Sheirer
2019-01-20 14:30:54 +00:00
committed by GitHub
parent 52e3d9d20d
commit 25d387f3cf
19 changed files with 1010 additions and 202 deletions

View File

@@ -1,7 +1,7 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,8 +27,10 @@ import io.github.dsheirer.preference.Preference;
import io.github.dsheirer.preference.PreferenceType;
import io.github.dsheirer.preference.identifier.talkgroup.APCO25TalkgroupFormatter;
import io.github.dsheirer.preference.identifier.talkgroup.FleetsyncTalkgroupFormatter;
import io.github.dsheirer.preference.identifier.talkgroup.LtrNetTalkgroupFormatter;
import io.github.dsheirer.preference.identifier.talkgroup.LTRTalkgroupFormatter;
import io.github.dsheirer.preference.identifier.talkgroup.MDC1200TalkgroupFormatter;
import io.github.dsheirer.preference.identifier.talkgroup.MPT1327TalkgroupFormatter;
import io.github.dsheirer.preference.identifier.talkgroup.PassportTalkgroupFormatter;
import io.github.dsheirer.protocol.Protocol;
import io.github.dsheirer.sample.Listener;
import org.slf4j.Logger;
@@ -135,10 +137,6 @@ public class TalkgroupFormatPreference extends Preference
return IntegerFormat.DECIMAL;
case FLEETSYNC:
return IntegerFormat.FORMATTED;
case IPV4:
return IntegerFormat.DECIMAL;
case LOJACK:
return IntegerFormat.DECIMAL;
case LTR:
return IntegerFormat.FORMATTED;
case LTR_NET:
@@ -151,8 +149,6 @@ public class TalkgroupFormatPreference extends Preference
return IntegerFormat.FORMATTED;
case PASSPORT:
return IntegerFormat.DECIMAL;
case TAIT1200:
return IntegerFormat.DECIMAL;
case UNKNOWN:
default:
return IntegerFormat.DECIMAL;
@@ -167,10 +163,6 @@ public class TalkgroupFormatPreference extends Preference
return true;
case FLEETSYNC:
return true;
case IPV4:
return true;
case LOJACK:
return true;
case LTR:
return true;
case LTR_NET:
@@ -183,8 +175,6 @@ public class TalkgroupFormatPreference extends Preference
return true;
case PASSPORT:
return false;
case TAIT1200:
return false;
case UNKNOWN:
default:
return true;
@@ -304,12 +294,21 @@ public class TalkgroupFormatPreference extends Preference
case FLEETSYNC:
return FleetsyncTalkgroupFormatter.format(talkgroupIdentifier, getTalkgroupFormat(Protocol.FLEETSYNC),
isTalkgroupFixedWidth(Protocol.FLEETSYNC));
case LTR_STANDARD:
return LTRTalkgroupFormatter.format(talkgroupIdentifier, getTalkgroupFormat(Protocol.LTR_STANDARD),
isTalkgroupFixedWidth(Protocol.LTR_STANDARD));
case LTR_NET:
return LtrNetTalkgroupFormatter.format(talkgroupIdentifier, getTalkgroupFormat(Protocol.LTR_NET),
return LTRTalkgroupFormatter.format(talkgroupIdentifier, getTalkgroupFormat(Protocol.LTR_NET),
isTalkgroupFixedWidth(Protocol.LTR_NET));
case MDC1200:
return MDC1200TalkgroupFormatter.format(talkgroupIdentifier, getTalkgroupFormat(Protocol.MDC1200),
isTalkgroupFixedWidth(Protocol.MDC1200));
case MPT1327:
return MPT1327TalkgroupFormatter.format(talkgroupIdentifier, getTalkgroupFormat(Protocol.MPT1327),
isTalkgroupFixedWidth(Protocol.MPT1327));
case PASSPORT:
return PassportTalkgroupFormatter.format(talkgroupIdentifier, getTalkgroupFormat(Protocol.PASSPORT),
isTalkgroupFixedWidth(Protocol.PASSPORT));
default:
return talkgroupIdentifier.toString();
}

View File

@@ -1,7 +1,7 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,17 +23,25 @@ package io.github.dsheirer.preference.identifier.talkgroup;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.module.decode.fleetsync2.identifier.FleetsyncIdentifier;
import io.github.dsheirer.preference.identifier.IntegerFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Formats Fleetsync 20-bit identifiers into either an integer value or an 8-bit fleet and 12-bit ident
*/
public class FleetsyncTalkgroupFormatter extends IntegerFormatter
{
private final static Logger mLog = LoggerFactory.getLogger(FleetsyncTalkgroupFormatter.class);
private static final int IDENTIFIER_DECIMAL_WIDTH = 7;
private static final int IDENTIFIER_HEXADECIMAL_WIDTH = 5;
private static final int FLEET_DECIMAL_WIDTH = 3;
private static final int IDENT_DECIMAL_WIDTH = 4;
private static final String SEPARATOR = "-";
private static final Pattern FLEETSYNC_PATTERN = Pattern.compile("(\\d{1,3})-(\\d{1,4})");
/**
* Formats the individual or group identifier to the specified format and width.
@@ -77,4 +85,72 @@ public class FleetsyncTalkgroupFormatter extends IntegerFormatter
return identifier.toString();
}
@Override
public String format(int talkgroup)
{
return toDecimal(getPrefix(talkgroup), FLEET_DECIMAL_WIDTH) + SEPARATOR +
toDecimal(getIdent(talkgroup), IDENT_DECIMAL_WIDTH);
}
@Override
public int parse(String formattedTalkgroup) throws ParseException
{
if(formattedTalkgroup != null)
{
Matcher m = FLEETSYNC_PATTERN.matcher(formattedTalkgroup);
if(m.matches())
{
String rawPrefix = m.group(1);
String rawIdent = m.group(2);
try
{
int prefix = Integer.parseInt(rawPrefix);
if(prefix < 1 || prefix > 127)
{
throw new ParseException("Fleetsync prefix must be in range 1-127. Error parsing [" + formattedTalkgroup + "]", 0);
}
int ident = Integer.parseInt(rawIdent);
if(ident < 1 || ident > 8191)
{
throw new ParseException("Fleetsync ident must be in range 1-8192. Error parsing [" + formattedTalkgroup + "]", 0);
}
return (prefix << 13) + ident;
}
catch(Exception e)
{
//exception is rethrown below
}
}
}
throw new ParseException("Error parsing value from fleetsync talkgroup [" + formattedTalkgroup + "]", 0);
}
/**
* Prefix for the specified talkgroup value
* @param talkgroup value containing a prefix
* @return prefix value
*/
public static int getPrefix(int talkgroup)
{
return (talkgroup >> 13) & 0x7F;
}
/**
* Ident for the specified talkgroup
* @param talkgroup containing an ident
* @return ident value
*/
public static int getIdent(int talkgroup)
{
return talkgroup & 0x1FFF;
}
}

View File

@@ -1,7 +1,7 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,8 @@ package io.github.dsheirer.preference.identifier.talkgroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
/**
* Base formatter class for integer values
*/
@@ -44,4 +46,34 @@ public class IntegerFormatter
{
return String.format("%0" + width + "d", value);
}
/**
* Formats the integer value for display as a string.
*
* Subclass implementations should override this method to return formatted values.
*/
public String format(int value)
{
return String.valueOf(value);
}
/**
* Parses an integer value from the formatted string value
*
* Subclass implementations should override this method to provide custom parsing of formatted values
*/
public int parse(String formattedValue) throws ParseException
{
try
{
return Integer.parseInt(formattedValue.trim());
}
catch(Exception e)
{
//exception re-thrown below
}
mLog.error("Throwing a parse exception for value [" + formattedValue + "]");
throw new ParseException("Error parsing integer value from [" + formattedValue + "]", 0);
}
}

View File

@@ -0,0 +1,163 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.preference.identifier.talkgroup;
import io.github.dsheirer.identifier.talkgroup.LTRTalkgroup;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.preference.identifier.IntegerFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Formats LTR identifiers
*/
public class LTRTalkgroupFormatter extends IntegerFormatter
{
private final static Logger mLog = LoggerFactory.getLogger(LTRTalkgroupFormatter.class);
private static final int IDENTIFIER_DECIMAL_WIDTH = 4;
private static final int IDENTIFIER_HEXADECIMAL_WIDTH = 4;
private static final int HOME_REPEATER_DECIMAL_WIDTH = 2;
private static final int TALKGROUP_DECIMAL_WIDTH = 3;
private static final String SEPARATOR = "-";
private static final Pattern LTR_PATTERN = Pattern.compile("(\\d{1,2})-(\\d{1,3})");
/**
* Formats the group identifier to the specified format and width.
*/
public static String format(TalkgroupIdentifier identifier, IntegerFormat format, boolean fixedWidth)
{
if(identifier instanceof LTRTalkgroup)
{
LTRTalkgroup ltr = (LTRTalkgroup)identifier;
if(fixedWidth)
{
switch(format)
{
case DECIMAL:
return toDecimal(ltr.getValue(), IDENTIFIER_DECIMAL_WIDTH);
case FORMATTED:
return toDecimal(ltr.getHomeChannel(), HOME_REPEATER_DECIMAL_WIDTH) + SEPARATOR +
toDecimal(ltr.getTalkgroup(), TALKGROUP_DECIMAL_WIDTH);
case HEXADECIMAL:
return toHex(ltr.getValue(), IDENTIFIER_HEXADECIMAL_WIDTH);
default:
throw new IllegalArgumentException("Unrecognized integer format: " + format);
}
}
else
{
switch(format)
{
case DECIMAL:
return ltr.toString();
case FORMATTED:
return ltr.getHomeChannel() + SEPARATOR + ltr.getTalkgroup();
case HEXADECIMAL:
return toHex(identifier.getValue());
default:
throw new IllegalArgumentException("Unrecognized integer format: " + format);
}
}
}
return identifier.toString();
}
/**
* Parses an integer value from a formatted talkgroup string (e.g. 12-243)
*/
public int parse(String formattedTalkgroup) throws ParseException
{
if(formattedTalkgroup != null)
{
Matcher m = LTR_PATTERN.matcher(formattedTalkgroup);
if(m.matches())
{
String rawLcn = m.group(1);
String rawGroup = m.group(2);
try
{
int lcn = Integer.parseInt(rawLcn);
if(lcn < 1 || lcn > 20)
{
throw new ParseException("LTR repeater must be in range 1-20. Error parsing [" + formattedTalkgroup + "]", 0);
}
int group = Integer.parseInt(rawGroup);
if(group < 0 || group > 255)
{
throw new ParseException("LTR talkgroup must be in range 1-255. Error parsing [" + formattedTalkgroup + "]", 0);
}
return (lcn << 8) + group;
}
catch(Exception e)
{
//exception is rethrown below
}
}
}
throw new ParseException("Error parsing LTR talkgroup [" + formattedTalkgroup + "]", 0);
}
/**
* Formats the talkgroup as a string
* @param talkgroup to format
* @return formatted talkgroup
*/
public String format(int talkgroup)
{
return toDecimal(getLcn(talkgroup), HOME_REPEATER_DECIMAL_WIDTH) + SEPARATOR +
toDecimal(getTalkgroup(talkgroup), TALKGROUP_DECIMAL_WIDTH);
}
/**
* LCN for the specified talkgroup value
* @param value containing an LCN prefix
* @return lcn value
*/
public static int getLcn(int value)
{
return (value >> 8) & 0x1F;
}
/**
* Talkgroup value for the specified composite talkgroup
* @param value containing an LCN and talkgroup value
* @return talkgroup value
*/
public static int getTalkgroup(int value)
{
return value & 0xFF;
}
}

View File

@@ -1,80 +0,0 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General 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.preference.identifier.talkgroup;
import io.github.dsheirer.identifier.talkgroup.LTRTalkgroup;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.preference.identifier.IntegerFormat;
/**
* Formats Fleetsync 20-bit identifiers into either an integer value or an 8-bit fleet and 12-bit ident
*/
public class LtrNetTalkgroupFormatter extends IntegerFormatter
{
private static final int IDENTIFIER_DECIMAL_WIDTH = 4;
private static final int IDENTIFIER_HEXADECIMAL_WIDTH = 4;
private static final int HOME_REPEATER_DECIMAL_WIDTH = 2;
private static final int TALKGROUP_DECIMAL_WIDTH = 3;
private static final String SEPARATOR = "-";
/**
* Formats the individual or group identifier to the specified format and width.
*/
public static String format(TalkgroupIdentifier identifier, IntegerFormat format, boolean fixedWidth)
{
if(identifier instanceof LTRTalkgroup)
{
LTRTalkgroup ltrnet = (LTRTalkgroup)identifier;
if(fixedWidth)
{
switch(format)
{
case DECIMAL:
return toDecimal(ltrnet.getValue(), IDENTIFIER_DECIMAL_WIDTH);
case FORMATTED:
return toDecimal(ltrnet.getHomeChannel(), HOME_REPEATER_DECIMAL_WIDTH) + SEPARATOR +
toDecimal(ltrnet.getTalkgroup(), TALKGROUP_DECIMAL_WIDTH);
case HEXADECIMAL:
return toHex(ltrnet.getValue(), IDENTIFIER_HEXADECIMAL_WIDTH);
default:
throw new IllegalArgumentException("Unrecognized integer format: " + format);
}
}
else
{
switch(format)
{
case DECIMAL:
return ltrnet.toString();
case FORMATTED:
return ltrnet.getHomeChannel() + SEPARATOR + ltrnet.getTalkgroup();
case HEXADECIMAL:
return toHex(identifier.getValue());
default:
throw new IllegalArgumentException("Unrecognized integer format: " + format);
}
}
}
return identifier.toString();
}
}

View File

@@ -0,0 +1,62 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.preference.identifier.talkgroup;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.preference.identifier.IntegerFormat;
public class MDC1200TalkgroupFormatter extends IntegerFormatter
{
public static final int DECIMAL_WIDTH = 5;
public static final int HEXADECIMAL_WIDTH = 4;
/**
* Formats the individual or group identifier to the specified format and width.
*/
public static String format(TalkgroupIdentifier identifier, IntegerFormat format, boolean fixedWidth)
{
if(fixedWidth)
{
switch(format)
{
case DECIMAL:
return toDecimal(identifier.getValue(), DECIMAL_WIDTH);
case HEXADECIMAL:
return toHex(identifier.getValue(), HEXADECIMAL_WIDTH);
default:
throw new IllegalArgumentException("Unrecognized integer format: " + format);
}
}
else
{
switch(format)
{
case DECIMAL:
case FORMATTED:
return identifier.getValue().toString();
case HEXADECIMAL:
return toHex(identifier.getValue());
default:
throw new IllegalArgumentException("Unrecognized integer format: " + format);
}
}
}
}

View File

@@ -1,7 +1,7 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,17 +23,26 @@ package io.github.dsheirer.preference.identifier.talkgroup;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.module.decode.mpt1327.identifier.MPT1327Talkgroup;
import io.github.dsheirer.preference.identifier.IntegerFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Formats Fleetsync 20-bit identifiers into either an integer value or an 8-bit fleet and 12-bit ident
*/
public class MPT1327TalkgroupFormatter extends IntegerFormatter
{
private final static Logger mLog = LoggerFactory.getLogger(MPT1327TalkgroupFormatter.class);
private static final int IDENTIFIER_DECIMAL_WIDTH = 7;
private static final int IDENTIFIER_HEXADECIMAL_WIDTH = 5;
private static final int FLEET_DECIMAL_WIDTH = 3;
private static final int IDENT_DECIMAL_WIDTH = 4;
private static final String SEPARATOR = "-";
private static final Pattern MPT1327_PATTERN = Pattern.compile("(\\d{1,3})-(\\d{1,4})");
/**
* Formats the individual or group identifier to the specified format and width.
@@ -77,4 +86,78 @@ public class MPT1327TalkgroupFormatter extends IntegerFormatter
return identifier.toString();
}
/**
* Parses an integer value from a formatted talkgroup string (e.g. 123-4567)
*/
public int parse(String formattedTalkgroup) throws ParseException
{
if(formattedTalkgroup != null)
{
Matcher m = MPT1327_PATTERN.matcher(formattedTalkgroup);
if(m.matches())
{
String rawPrefix = m.group(1);
String rawIdent = m.group(2);
try
{
int prefix = Integer.parseInt(rawPrefix);
if(prefix < 0 || prefix > 127)
{
throw new ParseException("MPT-1327 prefix must be in range 0-127. Error parsing [" + formattedTalkgroup + "]", 0);
}
int ident = Integer.parseInt(rawIdent);
if(ident < 1 || ident > 8191)
{
throw new ParseException("MPT-1327 ident must be in range 1-8192. Error parsing [" + formattedTalkgroup + "]", 0);
}
return (prefix << 13) + ident;
}
catch(Exception e)
{
//exception is rethrown below
}
}
}
throw new ParseException("Error parsing MPT1327 talkgroup value [" + formattedTalkgroup + "]", 0);
}
/**
* Formats the MPT-1327 talkgroup as a string
* @param talkgroup to format
* @return formatted talkgroup
*/
public String format(int talkgroup)
{
return toDecimal(getPrefix(talkgroup), FLEET_DECIMAL_WIDTH) + SEPARATOR + toDecimal(getIdent(talkgroup), IDENT_DECIMAL_WIDTH);
}
/**
* Prefix for the specified talkgroup value
* @param talkgroup value containing a prefix
* @return prefix value
*/
public static int getPrefix(int talkgroup)
{
return (talkgroup >> 13) & 0x7F;
}
/**
* Ident for the specified talkgroup
* @param talkgroup containing an ident
* @return ident value
*/
public static int getIdent(int talkgroup)
{
return talkgroup & 0x1FFF;
}
}

View File

@@ -0,0 +1,62 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* *****************************************************************************
*/
package io.github.dsheirer.preference.identifier.talkgroup;
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.preference.identifier.IntegerFormat;
public class PassportTalkgroupFormatter extends IntegerFormatter
{
public static final int DECIMAL_WIDTH = 5;
public static final int HEXADECIMAL_WIDTH = 4;
/**
* Formats the individual or group identifier to the specified format and width.
*/
public static String format(TalkgroupIdentifier identifier, IntegerFormat format, boolean fixedWidth)
{
if(fixedWidth)
{
switch(format)
{
case DECIMAL:
return toDecimal(identifier.getValue(), DECIMAL_WIDTH);
case HEXADECIMAL:
return toHex(identifier.getValue(), HEXADECIMAL_WIDTH);
default:
throw new IllegalArgumentException("Unrecognized integer format: " + format);
}
}
else
{
switch(format)
{
case DECIMAL:
case FORMATTED:
return identifier.getValue().toString();
case HEXADECIMAL:
return toHex(identifier.getValue());
default:
throw new IllegalArgumentException("Unrecognized integer format: " + format);
}
}
}
}