diff --git a/src/main/java/io/github/dsheirer/alias/AliasList.java b/src/main/java/io/github/dsheirer/alias/AliasList.java index 5ac8a4d6..e8482f24 100644 --- a/src/main/java/io/github/dsheirer/alias/AliasList.java +++ b/src/main/java/io/github/dsheirer/alias/AliasList.java @@ -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 @@ -284,7 +284,7 @@ public class AliasList implements Listener { Alias patchedAlias = patchGroupAliasList.getAlias(patchedGroup); - if(patchedAlias != null) + if(patchedAlias != null && !aliases.contains(patchedAlias)) { aliases.add(patchedAlias); } diff --git a/src/main/java/io/github/dsheirer/alias/id/talkgroup/Talkgroup.java b/src/main/java/io/github/dsheirer/alias/id/talkgroup/Talkgroup.java index 7562ef84..a10a713c 100644 --- a/src/main/java/io/github/dsheirer/alias/id/talkgroup/Talkgroup.java +++ b/src/main/java/io/github/dsheirer/alias/id/talkgroup/Talkgroup.java @@ -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 @@ -30,7 +30,7 @@ import io.github.dsheirer.protocol.Protocol; */ public class Talkgroup extends AliasID { - private Protocol mProtocol; + private Protocol mProtocol = Protocol.UNKNOWN; private int mValue; public Talkgroup() @@ -69,14 +69,21 @@ public class Talkgroup extends AliasID @Override public boolean isValid() { - return mValue != 0; + if(mProtocol == null || mProtocol == Protocol.UNKNOWN) + { + return false; + } + + TalkgroupFormat talkgroupFormat = TalkgroupFormat.get(mProtocol); + return talkgroupFormat.getMinimumValidValue() <= mValue && mValue <= talkgroupFormat.getMaximumValidValue(); } public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("Talkgroup:").append(mValue).append(" Protocol:").append((mProtocol != null ? mProtocol : "(unspecified)")); + sb.append("Talkgroup:").append(TalkgroupFormatter.format(mProtocol, mValue)); + sb.append(" Protocol:").append((mProtocol)); if(!isValid()) { diff --git a/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupEditor.java b/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupEditor.java index 68132da5..72f1203d 100644 --- a/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupEditor.java +++ b/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupEditor.java @@ -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 @@ -29,27 +29,32 @@ import org.slf4j.LoggerFactory; import javax.swing.DefaultComboBoxModel; import javax.swing.JComboBox; import javax.swing.JFormattedTextField; +import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.text.MaskFormatter; import java.awt.Color; import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.text.ParseException; public class TalkgroupEditor extends DocumentListenerEditor { private final static Logger mLog = LoggerFactory.getLogger(TalkgroupEditor.class); - private static final long serialVersionUID = 1L; - private static final String HELP_TEXT = - "

Talkgroup Identifier

"; - + private static final String VALID_CHARACTERS_FOR_ASTERISK_MASKS = "0123456789 "; + private MaskFormatter mMaskFormatter = new MaskFormatter(); private JComboBox mComboProtocol; private JFormattedTextField mTalkgroupField; + public TalkgroupEditor(AliasID aliasID) { initGUI(); @@ -62,7 +67,7 @@ public class TalkgroupEditor extends DocumentListenerEditor add(new JLabel("Protocol:")); - mComboProtocol = new JComboBox(); + mComboProtocol = new JComboBox<>(); DefaultComboBoxModel model = new DefaultComboBoxModel<>(); @@ -77,10 +82,9 @@ public class TalkgroupEditor extends DocumentListenerEditor @Override public void actionPerformed(ActionEvent e) { - Protocol selected = mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex()); + Protocol protocol = (Protocol)mComboProtocol.getSelectedItem(); + updateEditor(protocol); setModified(true); -// ValidatingEditor editor = DecoderFactory.getEditor(selected, mChannelMapModel); -// setEditor(editor); } }); @@ -88,11 +92,8 @@ public class TalkgroupEditor extends DocumentListenerEditor add(new JLabel("Value:")); - mTalkgroupField = new JFormattedTextField(); - mTalkgroupField.setColumns(10); - mTalkgroupField.setValue(new Integer(0)); + mTalkgroupField = new JFormattedTextField(mMaskFormatter); mTalkgroupField.getDocument().addDocumentListener(this); - mTalkgroupField.setToolTipText(HELP_TEXT); add(mTalkgroupField, "growx,push"); JLabel help = new JLabel("Help ..."); @@ -103,13 +104,50 @@ public class TalkgroupEditor extends DocumentListenerEditor @Override public void mouseClicked(MouseEvent e) { + TalkgroupFormat talkgroupFormat = TalkgroupFormat.get(getCurrentProtocol()); JOptionPane.showMessageDialog(TalkgroupEditor.this, - HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE); + talkgroupFormat.getValidRangeHelpText(), "Help", JOptionPane.INFORMATION_MESSAGE); } }); add(help, "align left"); } + private void updateEditor(Protocol protocol) + { + TalkgroupFormat mask = TalkgroupFormat.get(protocol); + int currentValue = 0; + Talkgroup talkgroup = getTalkgroup(); + + if(talkgroup != null) + { + currentValue = talkgroup.getValue(); + } + + try + { + mTalkgroupField.setValue(null); + mTalkgroupField.setToolTipText(mask.getValidRangeHelpText()); + mMaskFormatter.setMask(mask.getMask()); + if(mask.getMask().contains("*")) + { + mMaskFormatter.setValidCharacters(VALID_CHARACTERS_FOR_ASTERISK_MASKS); + } + mTalkgroupField.setValue(TalkgroupFormatter.format(protocol, currentValue)); + } + catch(ParseException pe) + { + mLog.error("Error applying talkgroup editor mask to mask formatter [" + mask.getMask() + "]"); + } + } + + private Protocol getCurrentProtocol() + { + return mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex()); + } + + /** + * Current talkgroup alias id + */ public Talkgroup getTalkgroup() { if(getItem() instanceof Talkgroup) @@ -129,8 +167,20 @@ public class TalkgroupEditor extends DocumentListenerEditor if(talkgroup != null) { - mComboProtocol.setSelectedItem(talkgroup.getProtocol()); - mTalkgroupField.setValue(new Integer(talkgroup.getValue())); + Protocol currentProtocol = getCurrentProtocol(); + if(currentProtocol == talkgroup.getProtocol()) + { + updateEditor(talkgroup.getProtocol()); + } + mComboProtocol.getModel().setSelectedItem(talkgroup.getProtocol()); + + String formatted = TalkgroupFormatter.format(talkgroup.getProtocol(), talkgroup.getValue()); + mTalkgroupField.setValue(formatted); + } + else + { + mComboProtocol.getModel().setSelectedItem(Protocol.UNKNOWN); + mTalkgroupField.setValue(TalkgroupFormatter.format(getCurrentProtocol(), 0)); } setModified(false); @@ -145,20 +195,63 @@ public class TalkgroupEditor extends DocumentListenerEditor if(talkgroup != null) { - Protocol selected = mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex()); - talkgroup.setProtocol(selected); + Protocol protocol = mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex()); + + int value = -1; try { - int value = ((Number)mTalkgroupField.getValue()).intValue(); + value = TalkgroupFormatter.parse(protocol, mTalkgroupField.getText()); + } + catch(ParseException pe) + { + //ignore ... value is still -1 and outside valid value range + } + + TalkgroupFormat mask = TalkgroupFormat.get(protocol); + + //Check for valid value within range ... notify user but allow value to persist + if(value < mask.getMinimumValidValue() || value > mask.getMaximumValidValue()) + { + String message = "Invalid value [" + mTalkgroupField.getText() + "]. " + protocol.name() + + " valid range is [" + mask.getValidRangeDescription() + "]"; + + JOptionPane.showMessageDialog(TalkgroupEditor.this, message, "Invalid Talkgroup Value", + JOptionPane.ERROR_MESSAGE); + } + else + { talkgroup.setValue(value); } - catch(Exception e) - { - mLog.error("Error parsing minimum talkgroup value from [" + mTalkgroupField.getValue() + "]"); - } + + talkgroup.setProtocol(protocol); } setModified(false); } + + public static void main(String[] args) + { + Talkgroup talkgroup = new Talkgroup(); + talkgroup.setProtocol(Protocol.APCO25); + talkgroup.setValue(12345678 ); + + JFrame frame = new JFrame("Talkgroup Editor"); + frame.setSize(new Dimension(500, 400)); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + JPanel panel = new JPanel(); + TalkgroupEditor talkgroupEditor = new TalkgroupEditor(null); + panel.add(talkgroupEditor); + frame.setContentPane(panel); + + EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + frame.setVisible(true); + talkgroupEditor.setItem(talkgroup); + } + }); + } } diff --git a/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupFormat.java b/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupFormat.java new file mode 100644 index 00000000..213ffd6d --- /dev/null +++ b/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupFormat.java @@ -0,0 +1,124 @@ +/* + * ****************************************************************************** + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.alias.id.talkgroup; + +import io.github.dsheirer.protocol.Protocol; + +/** + * Talkgroup protocol identifier entry masks and min/max valid ranges and valid range descriptions + * + * Note: the getMask() value is intended for use with a MaskFormatter attached to a JFormattedTextField. The + * protocol masks that have a dash (-) use the # (any digit) character and the protocol masks that do not have + * a formatting dash use an asterisk (*). Within the editor(s) that use this enumeration, the editor must use + * a setValidCharacters() on the mask formatter whenever it detects the mask containing one or more asterisks. + */ +public enum TalkgroupFormat +{ + APCO25("********", 1, 0xFFFFFF, "1 to 16,777,215", + "APCO25 valid range is 1 to 65,535(talkgroup)
or 1 to 16,777,215 (radio ID)"), + FLEETSYNC("###-####", 1, 0x7FFFFF, "001-0001 to 127-8192", + "Fleetsync valid ranges are 1-127(prefix)
and 1-8192(ident) (ie. 001-0001 to 127-8192)"), + LTR("##-###", 257, 5375, "01-001 to 20-255", + "LTR valid ranges are 1-20(repeater) and 1-255(talkgroup) (ie. 01-001 to 20-255)"), + MDC1200("*****", 1, 0xFFFF, "1 to 65,535", + "MDC-1200 valid value range is 1-65,535"), + MPT1327("###-####", 1, 0x7FFFFF, "000-0001 to 127-8192", + "MPT-1327 valid ranges are 0-127(prefix)
and 1-8192(ident) (ie. 000-0001 to 127-8192)"), + PASSPORT("*****", 1, 0xFFFF, "1 to 65,535", + "Passport valid value range is 1-65,535"), + UNKNOWN("********", 1, 0xFFFFFF, "1 to 16,777,215", + "Unknown protocol valid value range is 1-16,777,215"); + + private String mMask; + private int mMinimumValue; + private int mMaximumValue; + private String mValidRangeDescription; + private String mValidRangeHelpText; + + TalkgroupFormat(String mask, int minimumValue, int maximumValue, String validRangeDescription, String validRangeHelpText) + { + mMask = mask; + mMinimumValue = minimumValue; + mMaximumValue = maximumValue; + mValidRangeDescription = validRangeDescription; + mValidRangeHelpText = validRangeHelpText; + } + + public String getMask() + { + return mMask; + } + + /** + * Minimum valid value for the protocol + */ + public int getMinimumValidValue() + { + return mMinimumValue; + } + + /** + * Maximum valid value for the protocol + */ + public int getMaximumValidValue() + { + return mMaximumValue; + } + + /** + * Short description of the valid value range + */ + public String getValidRangeDescription() + { + return mValidRangeDescription; + } + + /** + * Help text for valid value ranges + */ + public String getValidRangeHelpText() + { + return mValidRangeHelpText; + } + + public static TalkgroupFormat get(Protocol prococol) + { + switch(prococol) + { + case APCO25: + return APCO25; + case FLEETSYNC: + return FLEETSYNC; + case LTR: + case LTR_NET: + case LTR_STANDARD: + return LTR; + case MDC1200: + return MDC1200; + case MPT1327: + return MPT1327; + case PASSPORT: + return PASSPORT; + default: + return UNKNOWN; + } + } +} diff --git a/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupFormatter.java b/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupFormatter.java new file mode 100644 index 00000000..20cd88b0 --- /dev/null +++ b/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupFormatter.java @@ -0,0 +1,93 @@ +/* + * ****************************************************************************** + * 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 + * ***************************************************************************** + */ + +package io.github.dsheirer.alias.id.talkgroup; + +import io.github.dsheirer.preference.identifier.talkgroup.APCO25TalkgroupFormatter; +import io.github.dsheirer.preference.identifier.talkgroup.FleetsyncTalkgroupFormatter; +import io.github.dsheirer.preference.identifier.talkgroup.IntegerFormatter; +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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.ParseException; +import java.util.HashMap; +import java.util.Map; + +/** + * Protocol-specific formatting of talkgroup values and parsing of formatted talkgroup values. + */ +public class TalkgroupFormatter +{ + private final static Logger mLog = LoggerFactory.getLogger(TalkgroupFormatter.class); + private static Map mFormatterMap = new HashMap<>(); + + static + { + mFormatterMap.put(Protocol.APCO25, new APCO25TalkgroupFormatter()); + mFormatterMap.put(Protocol.FLEETSYNC, new FleetsyncTalkgroupFormatter()); + LTRTalkgroupFormatter ltr = new LTRTalkgroupFormatter(); + mFormatterMap.put(Protocol.LTR, ltr); + mFormatterMap.put(Protocol.LTR_NET, ltr); + mFormatterMap.put(Protocol.LTR_STANDARD, ltr); + mFormatterMap.put(Protocol.MDC1200, new MDC1200TalkgroupFormatter()); + mFormatterMap.put(Protocol.MPT1327, new MPT1327TalkgroupFormatter()); + mFormatterMap.put(Protocol.PASSPORT, new PassportTalkgroupFormatter()); + mFormatterMap.put(Protocol.UNKNOWN, new IntegerFormatter()); + } + + public TalkgroupFormatter() + { + } + + /** + * Parses the formatted value into an integer using a protocol specific formatter + */ + public static int parse(Protocol protocol, String value) throws ParseException + { + IntegerFormatter formatter = mFormatterMap.get(protocol); + + if(formatter == null) + { + formatter = mFormatterMap.get(Protocol.UNKNOWN); + } + + return formatter.parse(value); + } + + /** + * Formats the integer value using a protocol-specific formatter + */ + public static String format(Protocol protocol, int value) + { + IntegerFormatter formatter = mFormatterMap.get(protocol); + + if(formatter == null) + { + formatter = mFormatterMap.get(Protocol.UNKNOWN); + } + + return formatter.format(value); + } +} diff --git a/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupRange.java b/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupRange.java index 1f2df81d..c3c740b8 100644 --- a/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupRange.java +++ b/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupRange.java @@ -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 @@ -30,7 +30,7 @@ import io.github.dsheirer.protocol.Protocol; */ public class TalkgroupRange extends AliasID { - private Protocol mProtocol; + private Protocol mProtocol = Protocol.UNKNOWN; private int mMinTalkgroup; private int mMaxTalkgroup; @@ -88,15 +88,25 @@ public class TalkgroupRange extends AliasID @Override public boolean isValid() { - return mProtocol != null && mMinTalkgroup != 0 && mMaxTalkgroup != 0 && mMinTalkgroup <= mMaxTalkgroup; + if(mProtocol == null || mProtocol == Protocol.UNKNOWN) + { + return false; + } + + TalkgroupFormat talkgroupFormat = TalkgroupFormat.get(mProtocol); + return talkgroupFormat.getMinimumValidValue() <= mMinTalkgroup && + mMinTalkgroup <= talkgroupFormat.getMaximumValidValue() && + talkgroupFormat.getMinimumValidValue() <= mMaxTalkgroup && + mMaxTalkgroup <= talkgroupFormat.getMaximumValidValue(); } public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("Talkgroup Range:").append(mMinTalkgroup).append(" to ").append(mMaxTalkgroup) - .append(" Protocol:").append(mProtocol == null ? "unspecified" : mProtocol); + sb.append("Talkgroup Range:").append(TalkgroupFormatter.format(mProtocol, mMinTalkgroup)); + sb.append(" to ").append(TalkgroupFormatter.format(mProtocol, mMaxTalkgroup)); + sb.append(" Protocol:").append(mProtocol != null ? mProtocol : "unspecified"); if(!isValid()) { diff --git a/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupRangeEditor.java b/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupRangeEditor.java index 0f1c613b..1e00361e 100644 --- a/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupRangeEditor.java +++ b/src/main/java/io/github/dsheirer/alias/id/talkgroup/TalkgroupRangeEditor.java @@ -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 @@ -31,21 +31,22 @@ import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.JOptionPane; +import javax.swing.text.MaskFormatter; import java.awt.Color; import java.awt.Cursor; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.text.ParseException; public class TalkgroupRangeEditor extends DocumentListenerEditor { private final static Logger mLog = LoggerFactory.getLogger(TalkgroupRangeEditor.class); private static final long serialVersionUID = 1L; - private static final String HELP_TEXT = - "

Talkgroup Range Identifier

Identifies a range of talkgroup values"; - + private static final String VALID_CHARACTERS_FOR_ASTERISK_MASKS = "0123456789 "; + private MaskFormatter mMaskFormatter = new MaskFormatter(); private JComboBox mComboProtocol; private JFormattedTextField mMinTalkgroupField; private JFormattedTextField mMaxTalkgroupField; @@ -78,10 +79,9 @@ public class TalkgroupRangeEditor extends DocumentListenerEditor @Override public void actionPerformed(ActionEvent e) { - Protocol selected = mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex()); + Protocol protocol = (Protocol)mComboProtocol.getSelectedItem(); + updateEditor(protocol); setModified(true); -// ValidatingEditor editor = DecoderFactory.getEditor(selected, mChannelMapModel); -// setEditor(editor); } }); @@ -89,20 +89,14 @@ public class TalkgroupRangeEditor extends DocumentListenerEditor add(new JLabel("Min:")); - mMinTalkgroupField = new JFormattedTextField(); - mMinTalkgroupField.setColumns(10); - mMinTalkgroupField.setValue(new Integer(0)); + mMinTalkgroupField = new JFormattedTextField(mMaskFormatter); mMinTalkgroupField.getDocument().addDocumentListener(this); - mMinTalkgroupField.setToolTipText(HELP_TEXT); add(mMinTalkgroupField, "growx,push"); add(new JLabel("Max:")); - mMaxTalkgroupField = new JFormattedTextField(); - mMaxTalkgroupField.setColumns(10); - mMaxTalkgroupField.setValue(new Integer(0)); + mMaxTalkgroupField = new JFormattedTextField(mMaskFormatter); mMaxTalkgroupField.getDocument().addDocumentListener(this); - mMaxTalkgroupField.setToolTipText(HELP_TEXT); add(mMaxTalkgroupField, "growx,push"); JLabel help = new JLabel("Help ..."); @@ -113,13 +107,56 @@ public class TalkgroupRangeEditor extends DocumentListenerEditor @Override public void mouseClicked(MouseEvent e) { + TalkgroupFormat talkgroupFormat = TalkgroupFormat.get(getCurrentProtocol()); JOptionPane.showMessageDialog(TalkgroupRangeEditor.this, - HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE); + talkgroupFormat.getValidRangeHelpText(), "Help", JOptionPane.INFORMATION_MESSAGE); } }); add(help, "align left"); } + private void updateEditor(Protocol protocol) + { + TalkgroupFormat mask = TalkgroupFormat.get(protocol); + int currentMinValue = 0; + int currentMaxValue = 0; + TalkgroupRange talkgroupRange = getTalkgroupRange(); + + if(talkgroupRange != null) + { + currentMinValue = talkgroupRange.getMinTalkgroup(); + currentMaxValue = talkgroupRange.getMaxTalkgroup(); + } + + try + { + mMinTalkgroupField.setValue(null); + mMaxTalkgroupField.setValue(null); + + mMinTalkgroupField.setToolTipText(mask.getValidRangeHelpText()); + mMaxTalkgroupField.setToolTipText(mask.getValidRangeHelpText()); + mMaskFormatter.setMask(mask.getMask()); + if(mask.getMask().contains("*")) + { + mMaskFormatter.setValidCharacters(VALID_CHARACTERS_FOR_ASTERISK_MASKS); + } + + mMinTalkgroupField.setValue(TalkgroupFormatter.format(protocol, currentMinValue)); + mMaxTalkgroupField.setValue(TalkgroupFormatter.format(protocol, currentMaxValue)); + } + catch(ParseException pe) + { + mLog.error("Error applying talkgroup editor mask to mask formatter [" + mask.getMask() + "]"); + } + } + + private Protocol getCurrentProtocol() + { + return mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex()); + } + + + public TalkgroupRange getTalkgroupRange() { if(getItem() instanceof TalkgroupRange) @@ -139,9 +176,17 @@ public class TalkgroupRangeEditor extends DocumentListenerEditor if(talkgroupRange != null) { - mComboProtocol.setSelectedItem(talkgroupRange.getProtocol()); - mMinTalkgroupField.setValue(new Integer(talkgroupRange.getMinTalkgroup())); - mMaxTalkgroupField.setValue(new Integer(talkgroupRange.getMaxTalkgroup())); + mComboProtocol.getModel().setSelectedItem(talkgroupRange.getProtocol()); + String minFormatted = TalkgroupFormatter.format(talkgroupRange.getProtocol(), talkgroupRange.getMinTalkgroup()); + mMinTalkgroupField.setValue(minFormatted); + String maxFormatted = TalkgroupFormatter.format(talkgroupRange.getProtocol(), talkgroupRange.getMaxTalkgroup()); + mMaxTalkgroupField.setValue(maxFormatted); + } + else + { + mComboProtocol.getModel().setSelectedItem(Protocol.UNKNOWN); + mMinTalkgroupField.setValue(TalkgroupFormatter.format(getCurrentProtocol(), 0)); + mMaxTalkgroupField.setValue(TalkgroupFormatter.format(getCurrentProtocol(), 0)); } setModified(false); @@ -156,28 +201,61 @@ public class TalkgroupRangeEditor extends DocumentListenerEditor if(talkgroupRange != null) { - Protocol selected = mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex()); - talkgroupRange.setProtocol(selected); + Protocol protocol = mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex()); + talkgroupRange.setProtocol(protocol); + + int minValue = -1; + int maxValue = -1; try { - int minTalkgroup = ((Number)mMinTalkgroupField.getValue()).intValue(); - talkgroupRange.setMinTalkgroup(minTalkgroup); + minValue = TalkgroupFormatter.parse(protocol, mMinTalkgroupField.getText()); } - catch(Exception e) + catch(ParseException pe) { - mLog.error("Error parsing minimum talkgroup value from [" + mMinTalkgroupField.getText() + "]"); + //ignore ... value is still -1 and outside valid value range } try { - int maxTalkgroup = ((Number)mMaxTalkgroupField.getValue()).intValue(); - talkgroupRange.setMaxTalkgroup(maxTalkgroup); + maxValue = TalkgroupFormatter.parse(protocol, mMaxTalkgroupField.getText()); } - catch(Exception e) + catch(ParseException pe) { - mLog.error("Error parsing maximum talkgroup value from [" + mMaxTalkgroupField.getText() + "]"); + //ignore ... value is still -1 and outside valid value range } + + TalkgroupFormat mask = TalkgroupFormat.get(protocol); + + //Check for valid value within range ... notify user but allow value to persist + if(minValue < mask.getMinimumValidValue() || minValue > mask.getMaximumValidValue()) + { + String message = "Invalid minimum value [" + mMinTalkgroupField.getText() + "]. " + protocol.name() + + " valid range is [" + mask.getValidRangeDescription() + "]"; + + JOptionPane.showMessageDialog(TalkgroupRangeEditor.this, message, + "Invalid Talkgroup Value", JOptionPane.ERROR_MESSAGE); + } + else + { + talkgroupRange.setMinTalkgroup(minValue); + } + + //Check for valid value within range ... notify user but allow value to persist + if(maxValue < mask.getMinimumValidValue() || maxValue > mask.getMaximumValidValue()) + { + String message = "Invalid maximum value [" + mMaxTalkgroupField.getText() + "]. " + protocol.name() + + " valid range is [" + mask.getValidRangeDescription() + "]"; + + JOptionPane.showMessageDialog(TalkgroupRangeEditor.this, message, + "Invalid Talkgroup Value", JOptionPane.ERROR_MESSAGE); + } + else + { + talkgroupRange.setMaxTalkgroup(maxValue); + } + + talkgroupRange.setProtocol(protocol); } setModified(false); diff --git a/src/main/java/io/github/dsheirer/gui/editor/DocumentListenerEditor.java b/src/main/java/io/github/dsheirer/gui/editor/DocumentListenerEditor.java index f5025e34..52fde41d 100644 --- a/src/main/java/io/github/dsheirer/gui/editor/DocumentListenerEditor.java +++ b/src/main/java/io/github/dsheirer/gui/editor/DocumentListenerEditor.java @@ -1,10 +1,29 @@ +/* + * ****************************************************************************** + * 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 + * ***************************************************************************** + */ + package io.github.dsheirer.gui.editor; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -public abstract class DocumentListenerEditor extends Editor - implements DocumentListener +public abstract class DocumentListenerEditor extends Editor implements DocumentListener { private static final long serialVersionUID = 1L; diff --git a/src/main/java/io/github/dsheirer/module/decode/mpt1327/identifier/MPT1327Talkgroup.java b/src/main/java/io/github/dsheirer/module/decode/mpt1327/identifier/MPT1327Talkgroup.java index 4294112b..fc1d2944 100644 --- a/src/main/java/io/github/dsheirer/module/decode/mpt1327/identifier/MPT1327Talkgroup.java +++ b/src/main/java/io/github/dsheirer/module/decode/mpt1327/identifier/MPT1327Talkgroup.java @@ -1,23 +1,28 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ****************************************************************************** + * 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 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. + * 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 - * - ******************************************************************************/ + * 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.mpt1327.identifier; import io.github.dsheirer.identifier.Role; import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier; +import io.github.dsheirer.preference.identifier.talkgroup.MPT1327TalkgroupFormatter; import io.github.dsheirer.protocol.Protocol; /** @@ -40,35 +45,19 @@ public class MPT1327Talkgroup extends TalkgroupIdentifier } /** - * This identifier formatted as PPP-IIII where P=prefix and I=ident - */ - public String formatted() - { - return String.format("%03d-%04d", getPrefix(), getIdent()); - } - - /** - * Prefix for the talkgroup + * Prefix for this talkgroup */ public int getPrefix() { - return (getValue() >> 13) & 0x7F; + return MPT1327TalkgroupFormatter.getPrefix(getValue()); } /** - * Ident for the talkgroup + * Ident for this talkgroup */ public int getIdent() { - return getValue() & 0x1FFF; - } - - /** - * Indicates the type of ident value - */ - public IdentType getIdentType() - { - return IdentType.fromIdent(getIdent()); + return MPT1327TalkgroupFormatter.getIdent(getValue()); } /** diff --git a/src/main/java/io/github/dsheirer/playlist/PlaylistUpdater.java b/src/main/java/io/github/dsheirer/playlist/PlaylistUpdater.java index 9add67fd..503f8779 100644 --- a/src/main/java/io/github/dsheirer/playlist/PlaylistUpdater.java +++ b/src/main/java/io/github/dsheirer/playlist/PlaylistUpdater.java @@ -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 @@ -25,11 +25,11 @@ import io.github.dsheirer.alias.id.AliasID; import io.github.dsheirer.alias.id.AliasIDType; import io.github.dsheirer.alias.id.legacy.fleetsync.FleetsyncID; import io.github.dsheirer.alias.id.legacy.mdc.MDC1200ID; +import io.github.dsheirer.alias.id.legacy.mobileID.Min; import io.github.dsheirer.alias.id.legacy.mpt1327.MPT1327ID; import io.github.dsheirer.alias.id.legacy.talkgroup.LegacyTalkgroupID; -import io.github.dsheirer.alias.id.legacy.mobileID.Min; -import io.github.dsheirer.alias.id.talkgroup.Talkgroup; import io.github.dsheirer.alias.id.legacy.uniqueID.UniqueID; +import io.github.dsheirer.alias.id.talkgroup.Talkgroup; import io.github.dsheirer.controller.channel.Channel; import io.github.dsheirer.module.log.EventLogType; import io.github.dsheirer.module.log.config.EventLogConfiguration; @@ -308,8 +308,6 @@ public class PlaylistUpdater { int value = Integer.valueOf(m.group(3)); value += (Integer.valueOf(m.group(2)) << 8); - value += (Integer.valueOf(m.group(1)) << 13); - toAdd.add(new Talkgroup(Protocol.LTR, value)); it.remove(); updated++; diff --git a/src/main/java/io/github/dsheirer/preference/identifier/TalkgroupFormatPreference.java b/src/main/java/io/github/dsheirer/preference/identifier/TalkgroupFormatPreference.java index fef1e13d..4a7039f1 100644 --- a/src/main/java/io/github/dsheirer/preference/identifier/TalkgroupFormatPreference.java +++ b/src/main/java/io/github/dsheirer/preference/identifier/TalkgroupFormatPreference.java @@ -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(); } diff --git a/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/FleetsyncTalkgroupFormatter.java b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/FleetsyncTalkgroupFormatter.java index 86fdaef9..b02ac232 100644 --- a/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/FleetsyncTalkgroupFormatter.java +++ b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/FleetsyncTalkgroupFormatter.java @@ -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; + } + } diff --git a/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/IntegerFormatter.java b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/IntegerFormatter.java index 2b5a71ac..bbfe37af 100644 --- a/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/IntegerFormatter.java +++ b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/IntegerFormatter.java @@ -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); + } } diff --git a/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/LTRTalkgroupFormatter.java b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/LTRTalkgroupFormatter.java new file mode 100644 index 00000000..371c6721 --- /dev/null +++ b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/LTRTalkgroupFormatter.java @@ -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 + * ***************************************************************************** + */ + +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; + } + +} diff --git a/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/LtrNetTalkgroupFormatter.java b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/LtrNetTalkgroupFormatter.java deleted file mode 100644 index f223049f..00000000 --- a/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/LtrNetTalkgroupFormatter.java +++ /dev/null @@ -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 - * ***************************************************************************** - */ - -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(); - } -} diff --git a/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/MDC1200TalkgroupFormatter.java b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/MDC1200TalkgroupFormatter.java new file mode 100644 index 00000000..9ceffd67 --- /dev/null +++ b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/MDC1200TalkgroupFormatter.java @@ -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 + * ***************************************************************************** + */ + +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); + } + } + } +} diff --git a/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/MPT1327TalkgroupFormatter.java b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/MPT1327TalkgroupFormatter.java index 6723123e..31c9b31d 100644 --- a/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/MPT1327TalkgroupFormatter.java +++ b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/MPT1327TalkgroupFormatter.java @@ -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; + } } diff --git a/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/PassportTalkgroupFormatter.java b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/PassportTalkgroupFormatter.java new file mode 100644 index 00000000..1266c558 --- /dev/null +++ b/src/main/java/io/github/dsheirer/preference/identifier/talkgroup/PassportTalkgroupFormatter.java @@ -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 + * ***************************************************************************** + */ + +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); + } + } + } +} diff --git a/src/main/java/io/github/dsheirer/protocol/Protocol.java b/src/main/java/io/github/dsheirer/protocol/Protocol.java index d25e6a93..e6d8d30a 100644 --- a/src/main/java/io/github/dsheirer/protocol/Protocol.java +++ b/src/main/java/io/github/dsheirer/protocol/Protocol.java @@ -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 @@ -52,7 +52,7 @@ public enum Protocol } public static EnumSet TALKGROUP_PROTOCOLS = EnumSet.of(APCO25, FLEETSYNC, LTR_NET, LTR_STANDARD, MDC1200, - MPT1327, PASSPORT, TAIT1200); + MPT1327, PASSPORT); @Override public String toString()