From e41e430e452122a154edd4b2e294b486eeb9dccc Mon Sep 17 00:00:00 2001 From: denny Date: Fri, 1 Jan 2016 09:03:04 -0500 Subject: [PATCH] Updates LoJack message/event function and reply code aliasing. -Adds new LoJack AliasID allowing user to specify a lojack function and 5-character reply code with wildcards. -Removes SiteID as an alias option for LoJack. Valid Alias IDs for LoJack now are: -LoJack Alias ID: for function and reply code combinations -ESN ID: for transponder addresses --- src/alias/AliasIDType.java | 1 + src/alias/AliasList.java | 59 +++++--- src/alias/AliasNode.java | 27 ++++ src/alias/id/lojack/LoJackFunctionAndID.java | 132 ++++++++++++++++++ src/alias/id/lojack/LoJackIDEditor.java | 123 ++++++++++++++++ src/alias/id/lojack/LoJackIDNode.java | 86 ++++++++++++ src/module/decode/event/CallEventPanel.java | 62 +++++--- .../decode/lj1200/LJ1200DecoderState.java | 2 +- src/module/decode/lj1200/LJ1200Message.java | 35 ++--- 9 files changed, 464 insertions(+), 63 deletions(-) create mode 100644 src/alias/id/lojack/LoJackFunctionAndID.java create mode 100644 src/alias/id/lojack/LoJackIDEditor.java create mode 100644 src/alias/id/lojack/LoJackIDNode.java diff --git a/src/alias/AliasIDType.java b/src/alias/AliasIDType.java index a03ca358..83bc887b 100644 --- a/src/alias/AliasIDType.java +++ b/src/alias/AliasIDType.java @@ -21,6 +21,7 @@ public enum AliasIDType { ESN, Fleetsync, + LoJack, LTRNetUID, MDC1200, MIN, diff --git a/src/alias/AliasList.java b/src/alias/AliasList.java index 7b0a6ced..312e9d6f 100644 --- a/src/alias/AliasList.java +++ b/src/alias/AliasList.java @@ -1,6 +1,6 @@ /******************************************************************************* * SDR Trunk - * Copyright (C) 2014 Dennis Sheirer + * Copyright (C) 2014,2015 Dennis Sheirer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,11 +19,14 @@ package alias; import java.util.ArrayList; import java.util.HashMap; +import java.util.Map; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSeeAlso; +import module.decode.lj1200.LJ1200Message.Function; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,6 +37,7 @@ import alias.action.script.ScriptAction; import alias.id.esn.Esn; import alias.id.fleetsync.FleetsyncID; import alias.id.fleetsync.StatusID; +import alias.id.lojack.LoJackFunctionAndID; import alias.id.mdc.MDC1200ID; import alias.id.mobileID.Min; import alias.id.mpt1327.MPT1327ID; @@ -51,6 +55,7 @@ import audio.metadata.MetadataType; FleetsyncID.class, Esn.class, Group.class, + LoJackFunctionAndID.class, MDC1200ID.class, Min.class, MPT1327ID.class, @@ -77,15 +82,16 @@ public class AliasList implements Comparable private String mName; private ArrayList mGroups = new ArrayList(); - private HashMap mESN = new HashMap(); - private HashMap mFleetsync = new HashMap(); - private HashMap mMDC1200 = new HashMap(); - private HashMap mMobileID = new HashMap(); - private HashMap mMPT1327 = new HashMap(); - private HashMap mSiteID = new HashMap(); - private HashMap mStatus = new HashMap(); - private HashMap mTalkgroup = new HashMap(); - private HashMap mUniqueID = new HashMap(); + private Map mESN = new HashMap<>(); + private Map mFleetsync = new HashMap<>(); + private Map mLoJack = new HashMap<>(); + private Map mMDC1200 = new HashMap<>(); + private Map mMobileID = new HashMap<>(); + private Map mMPT1327 = new HashMap<>(); + private Map mSiteID = new HashMap<>(); + private Map mStatus = new HashMap<>(); + private Map mTalkgroup = new HashMap<>(); + private Map mUniqueID = new HashMap<>(); private boolean mESNWildcard = false; private boolean mMobileIDWildcard = false; @@ -114,6 +120,7 @@ public class AliasList implements Comparable //Clear hashmaps mESN.clear(); mFleetsync.clear(); + mLoJack.clear(); mMDC1200.clear(); mMobileID.clear(); mMPT1327.clear(); @@ -157,6 +164,9 @@ public class AliasList implements Comparable mFleetsync.put( fs.getIdent(), alias ); } break; + case LoJack: + mLoJack.put( (LoJackFunctionAndID)id, alias ); + break; case MDC1200: MDC1200ID mdc = (MDC1200ID)id; @@ -242,6 +252,13 @@ public class AliasList implements Comparable mTalkgroup.put( tgid.getTalkgroup(), alias ); } break; + case NonRecordable: + case Priority: + //We don't maintain lookups for these items + break; + default: + mLog.warn( "Unrecognized Alias ID Type:" + id.getType().name() ); + break; } } } @@ -299,8 +316,6 @@ public class AliasList implements Comparable { if( esn != null ) { - Alias retVal = null; - if( mESNWildcard ) { for( String regex: mESN.keySet() ) @@ -325,8 +340,6 @@ public class AliasList implements Comparable { if( ident != null ) { - Alias retVal = null; - if( mFleetsyncWildcard ) { for( String regex: mFleetsync.keySet() ) @@ -346,12 +359,26 @@ public class AliasList implements Comparable return null; } + public Alias getLoJackAlias( Function function, String id ) + { + if( id != null ) + { + for( LoJackFunctionAndID lojack: mLoJack.keySet() ) + { + if( lojack.matches( function, id ) ) + { + return mLoJack.get( lojack ); + } + } + } + + return null; + } + public Alias getMDC1200Alias( String ident ) { if( ident != null ) { - Alias retVal = null; - if( mMDC1200Wildcard ) { for( String regex: mMDC1200.keySet() ) diff --git a/src/alias/AliasNode.java b/src/alias/AliasNode.java index 123347f0..43de7703 100644 --- a/src/alias/AliasNode.java +++ b/src/alias/AliasNode.java @@ -40,6 +40,8 @@ import alias.id.fleetsync.FleetsyncID; import alias.id.fleetsync.FleetsyncIDNode; import alias.id.fleetsync.StatusID; import alias.id.fleetsync.StatusIDNode; +import alias.id.lojack.LoJackFunctionAndID; +import alias.id.lojack.LoJackIDNode; import alias.id.mdc.MDC1200ID; import alias.id.mdc.MDC1200IDNode; import alias.id.mobileID.MINNode; @@ -109,6 +111,10 @@ public class AliasNode extends ConfigurableNode getModel().addNode( new FleetsyncIDNode( (FleetsyncID)aliasID ), AliasNode.this, getChildCount() ); break; + case LoJack: + getModel().addNode( new LoJackIDNode( (LoJackFunctionAndID)aliasID ), + AliasNode.this, getChildCount() ); + break; case LTRNetUID: getModel().addNode( new UniqueIDNode( (UniqueID)aliasID ), AliasNode.this, getChildCount() ); @@ -226,6 +232,27 @@ public class AliasNode extends ConfigurableNode } ); addIDMenu.add( addFleetsyncItem ); + JMenuItem addLoJackItem = new JMenuItem( "LoJack" ); + addLoJackItem.addActionListener( new ActionListener() + { + @Override + public void actionPerformed( ActionEvent e ) + { + LoJackFunctionAndID lj = new LoJackFunctionAndID(); + + getAlias().addAliasID( lj ); + + LoJackIDNode node = new LoJackIDNode( lj ); + + getModel().addNode( node, + AliasNode.this, + AliasNode.this.getChildCount() ); + + node.show(); + } + } ); + addIDMenu.add( addLoJackItem ); + JMenuItem addMDCItem = new JMenuItem( "MDC-1200" ); addMDCItem.addActionListener( new ActionListener() { diff --git a/src/alias/id/lojack/LoJackFunctionAndID.java b/src/alias/id/lojack/LoJackFunctionAndID.java new file mode 100644 index 00000000..99ee74b1 --- /dev/null +++ b/src/alias/id/lojack/LoJackFunctionAndID.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * SDR Trunk + * Copyright (C) 2015 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 alias.id.lojack; + +import javax.xml.bind.annotation.XmlAttribute; + +import module.decode.lj1200.LJ1200Message; +import module.decode.lj1200.LJ1200Message.Function; +import alias.AliasID; +import alias.AliasIDType; + +public class LoJackFunctionAndID extends AliasID +{ + private LJ1200Message.Function mFunction = Function.F0_UNKNOWN; + private String mID = "*****"; + + public LoJackFunctionAndID() + { + } + + @XmlAttribute( name="id" ) + public String getID() + { + return mID; + } + + public void setID( String id ) + { + mID = id; + } + + @XmlAttribute( name="function" ) + public Function getFunction() + { + return mFunction; + } + + public void setFunction( Function function ) + { + mFunction = function; + } + + public String toString() + { + return "LoJack FUNC: " + mFunction.getLabel() + " ID:" + ( mID == null ? "" : mID ); + } + + /** + * Indicates if the function and id combination match this alias id + */ + public boolean matches( Function function, String id ) + { + return mFunction == function && + mID != null && + id != null && + id.matches( mID.replace( "*", ".?" ) ); + } + + @Override + public boolean matches( AliasID id ) + { + boolean retVal = false; + + if( mID != null && id instanceof LoJackFunctionAndID ) + { + LoJackFunctionAndID otherLojack = (LoJackFunctionAndID)id; + + if( otherLojack.getFunction() == mFunction ) + { + //Create a pattern - replace * wildcards with regex single-char wildcard + String pattern = mID.replace( "*", ".?" ); + + retVal = otherLojack.getID().matches( pattern ); + } + } + + return retVal; + } + + @Override + public AliasIDType getType() + { + return AliasIDType.LoJack; + } + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = prime * result + + ( ( mFunction == null ) ? 0 : mFunction.hashCode() ); + result = prime * result + ( ( mID == null ) ? 0 : mID.hashCode() ); + return result; + } + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + return true; + if ( obj == null ) + return false; + if ( getClass() != obj.getClass() ) + return false; + LoJackFunctionAndID other = (LoJackFunctionAndID) obj; + if ( mFunction != other.mFunction ) + return false; + if ( mID == null ) + { + if ( other.mID != null ) + return false; + } else if ( !mID.equals( other.mID ) ) + return false; + return true; + } +} diff --git a/src/alias/id/lojack/LoJackIDEditor.java b/src/alias/id/lojack/LoJackIDEditor.java new file mode 100644 index 00000000..d8208635 --- /dev/null +++ b/src/alias/id/lojack/LoJackIDEditor.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * SDR Trunk + * Copyright (C) 2015 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 alias.id.lojack; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.JTextField; + +import module.decode.lj1200.LJ1200Message; +import module.decode.lj1200.LJ1200Message.Function; +import net.miginfocom.swing.MigLayout; +import controller.ConfigurableNode; + +public class LoJackIDEditor extends JPanel implements ActionListener +{ + private static final long serialVersionUID = 1L; + private LoJackIDNode mLoJackIDNode; + + private JComboBox mFunctionCombo; + private JTextField mTextIdent; + + private String mHelpText = "Select a LoJack message function code and enter" + + " a five character reply code or identifier in the ID field.\n\n" + + "Wildcard: use an asterisk (*) to wildcard any character in the " + + "five character reply code (e.g. AB*CD or ***12 or *****)\n\n"; + + public LoJackIDEditor( LoJackIDNode lojackNode ) + { + mLoJackIDNode = lojackNode; + initGUI(); + } + + private void initGUI() + { + setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][grow]" ) ); + + add( new JLabel( "LoJack Function and ID" ), "span,align center" ); + + LoJackFunctionAndID lojack = mLoJackIDNode.getLoJackID(); + + add( new JLabel( "Function:" ) ); + mFunctionCombo = new JComboBox( Function.values() ); + mFunctionCombo.setSelectedItem( lojack.getFunction() ); + add( mFunctionCombo, "grow, wrap" ); + + add( new JLabel( "ID:" ) ); + mTextIdent = new JTextField( lojack.getID() ); + + add( mTextIdent, "grow, wrap" ); + + JButton btnSave = new JButton( "Save" ); + btnSave.addActionListener( LoJackIDEditor.this ); + add( btnSave, "growx,push" ); + + JButton btnReset = new JButton( "Reset" ); + btnReset.addActionListener( LoJackIDEditor.this ); + add( btnReset, "growx,push" ); + + JTextArea helpText = new JTextArea( mHelpText ); + helpText.setLineWrap( true ); + helpText.setBackground( getBackground() ); + add( helpText, "span,grow,push" ); + } + + @Override + public void actionPerformed( ActionEvent e ) + { + String command = e.getActionCommand(); + + final LoJackFunctionAndID lojack = mLoJackIDNode.getLoJackID(); + + if( command.contentEquals( "Save" ) ) + { + String id = mTextIdent.getText(); + + if( id != null ) + { + + lojack.setID( id ); + lojack.setFunction( (Function)mFunctionCombo.getSelectedItem() ); + + ((ConfigurableNode)mLoJackIDNode.getParent()).sort(); + + mLoJackIDNode.save(); + + mLoJackIDNode.show(); + } + else + { + JOptionPane.showMessageDialog( LoJackIDEditor.this, "Please enter an ident" ); + } + } + else if( command.contentEquals( "Reset" ) ) + { + mFunctionCombo.setSelectedItem( lojack.getFunction() ); + mTextIdent.setText( lojack.getID() ); + } + + mLoJackIDNode.refresh(); + } +} diff --git a/src/alias/id/lojack/LoJackIDNode.java b/src/alias/id/lojack/LoJackIDNode.java new file mode 100644 index 00000000..3b4f3ed0 --- /dev/null +++ b/src/alias/id/lojack/LoJackIDNode.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * SDR Trunk + * Copyright (C) 2014 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 alias.id.lojack; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; + +import alias.AliasIDNode; +import alias.AliasNode; + +public class LoJackIDNode extends AliasIDNode +{ + private static final long serialVersionUID = 1L; + + public LoJackIDNode( LoJackFunctionAndID id ) + { + super( id ); + } + + @Override + public JPanel getEditor() + { + return new LoJackIDEditor( this ); + } + + public LoJackFunctionAndID getLoJackID() + { + return (LoJackFunctionAndID)getUserObject(); + } + + public String toString() + { + return getLoJackID().toString(); + } + + public JPopupMenu getContextMenu() + { + JPopupMenu retVal = new JPopupMenu(); + + JMenuItem deleteItem = new JMenuItem( "Delete" ); + deleteItem.addActionListener( new ActionListener() + { + @Override + public void actionPerformed( ActionEvent e ) + { + int n = JOptionPane.showConfirmDialog( getModel().getTree(), + "Are you sure you want to permanently delete this node?" ); + + if( n == JOptionPane.YES_OPTION ) + { + AliasNode parent = (AliasNode)getParent(); + + parent.getAlias().removeAliasID( getLoJackID() ); + + save(); + + getModel().removeNodeFromParent( LoJackIDNode.this ); + } + } + } ); + + retVal.add( deleteItem ); + + return retVal; + } +} diff --git a/src/module/decode/event/CallEventPanel.java b/src/module/decode/event/CallEventPanel.java index e163d3db..c56f53bf 100644 --- a/src/module/decode/event/CallEventPanel.java +++ b/src/module/decode/event/CallEventPanel.java @@ -17,6 +17,8 @@ ******************************************************************************/ package module.decode.event; +import java.awt.EventQueue; + import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; @@ -58,7 +60,7 @@ public class CallEventPanel extends JPanel implements ChannelEventListener } @Override - public void channelChanged( ChannelEvent event ) + public void channelChanged( final ChannelEvent event ) { if( event.getEvent() == Event.CHANGE_SELECTED && event.getChannel().isSelected() ) @@ -67,26 +69,34 @@ public class CallEventPanel extends JPanel implements ChannelEventListener ( mDisplayedChannel != null && mDisplayedChannel != event.getChannel() ) ) { - removeAll(); - - JTable table = new JTable( - event.getChannel().getCallEventModel() ); + EventQueue.invokeLater( new Runnable() + { + @Override + public void run() + { + removeAll(); + + JTable table = new JTable( + event.getChannel().getCallEventModel() ); - table.setAutoCreateRowSorter( true ); - table.setAutoResizeMode( JTable.AUTO_RESIZE_LAST_COLUMN ); - - table.getColumnModel().getColumn( CallEventModel.FROM_ALIAS ) - .setCellRenderer( mRenderer ); + table.setAutoCreateRowSorter( true ); + table.setAutoResizeMode( JTable.AUTO_RESIZE_LAST_COLUMN ); + + table.getColumnModel().getColumn( CallEventModel.FROM_ALIAS ) + .setCellRenderer( mRenderer ); - table.getColumnModel().getColumn( CallEventModel.TO_ALIAS ) - .setCellRenderer( mRenderer ); + table.getColumnModel().getColumn( CallEventModel.TO_ALIAS ) + .setCellRenderer( mRenderer ); + + add( new JScrollPane( table ) ); + + mDisplayedChannel = event.getChannel(); + + revalidate(); + repaint(); + } + } ); - add( new JScrollPane( table ) ); - - mDisplayedChannel = event.getChannel(); - - revalidate(); - repaint(); } } else if( event.getEvent() == Event.CHANNEL_PROCESSING_STOPPED || @@ -96,11 +106,19 @@ public class CallEventPanel extends JPanel implements ChannelEventListener mDisplayedChannel == event.getChannel() ) { mDisplayedChannel = null; - removeAll(); - add( mEmptyScroller ); + + EventQueue.invokeLater( new Runnable() + { + @Override + public void run() + { + removeAll(); + add( mEmptyScroller ); - revalidate(); - repaint(); + revalidate(); + repaint(); + } + } ); } } } diff --git a/src/module/decode/lj1200/LJ1200DecoderState.java b/src/module/decode/lj1200/LJ1200DecoderState.java index 0edba1e5..71b72f0f 100644 --- a/src/module/decode/lj1200/LJ1200DecoderState.java +++ b/src/module/decode/lj1200/LJ1200DecoderState.java @@ -87,7 +87,7 @@ public class LJ1200DecoderState extends DecoderState if( lj.isValid() ) { setAddress( lj.getAddress() ); - setAddressAlias( lj.getAddressAlias() ); + setAddressAlias( lj.getTransponderAlias() ); mAddresses.add( mAddress ); diff --git a/src/module/decode/lj1200/LJ1200Message.java b/src/module/decode/lj1200/LJ1200Message.java index de60cc26..64bc8ca3 100644 --- a/src/module/decode/lj1200/LJ1200Message.java +++ b/src/module/decode/lj1200/LJ1200Message.java @@ -17,7 +17,6 @@ ******************************************************************************/ package module.decode.lj1200; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; @@ -61,8 +60,6 @@ public class LJ1200Message extends Message public static int[] MESSAGE_CRC = { 79,78,77,76,75,74,73,72,71,70,69,68,67, 66,65,64 }; - private static SimpleDateFormat mSDF = new SimpleDateFormat( "yyyyMMdd HHmmss" ); - private BinaryMessage mMessage; private AliasList mAliasList; private CRC mCRC; @@ -126,7 +123,7 @@ public class LJ1200Message extends Message return mMessage.getHex( ADDRESS, 7 ); } - public Alias getAddressAlias() + public Alias getTransponderAlias() { if( mAliasList != null ) { @@ -136,21 +133,11 @@ public class LJ1200Message extends Message return null; } - public Alias getSiteAndReplyCodeAlias() + public Alias getFunctionAndIDAlias() { - Function function = getFunction(); - if( mAliasList != null ) { - if( function == Function.F1_SITE_ID || - function == Function.F1_SPEED_UP || - function == Function.F2_TEST || - function == Function.F3_DEACTIVATE || - function == Function.F4_ACTIVATE || - function == Function.FF_TRACK_PULSE ) - { - return mAliasList.getSiteID( getReplyCode() ); - } + return mAliasList.getLoJackAlias( getFunction(), getReplyCode() ); } return null; @@ -200,7 +187,7 @@ public class LJ1200Message extends Message sb.append( getReplyCode() ); - Alias site = getSiteAndReplyCodeAlias(); + Alias site = getFunctionAndIDAlias(); if( site != null ) { @@ -286,7 +273,7 @@ public class LJ1200Message extends Message @Override public Alias getFromIDAlias() { - return getSiteAndReplyCodeAlias(); + return getFunctionAndIDAlias(); } @Override @@ -415,18 +402,18 @@ public class LJ1200Message extends Message { List aliases = new ArrayList(); - Alias siteAndReply = getSiteAndReplyCodeAlias(); + Alias functionAndID = getFunctionAndIDAlias(); - if( siteAndReply != null ) + if( functionAndID != null ) { - aliases.add( siteAndReply ); + aliases.add( functionAndID ); } - Alias address = getAddressAlias(); + Alias transponder = getTransponderAlias(); - if( address != null ) + if( transponder != null ) { - aliases.add( address ); + aliases.add( transponder ); } return aliases;