android: AndrOBD library vendored (no submodule, no git link)
This commit is contained in:
+145
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Threaded FTP Loader class to be used for threaded reading of an FTP stream
|
||||
*
|
||||
* @author $Author: erwin $
|
||||
* @version $Id: FtpLoader.java,v 1.7 2009-11-21 21:33:15 erwin Exp $
|
||||
*/
|
||||
public class FtpLoader extends URLConnection
|
||||
implements Runnable
|
||||
{
|
||||
/** reader object to read from stream */
|
||||
private BufferedReader rdr = null;
|
||||
|
||||
/** List of telegram listeners */
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final Vector TelegramListeners = new Vector();
|
||||
|
||||
/**
|
||||
* class constructor
|
||||
*/
|
||||
private FtpLoader(String newUrl)
|
||||
throws MalformedURLException
|
||||
{
|
||||
super(new URL(newUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* connect to URL and start threaded loading
|
||||
*/
|
||||
public void connect()
|
||||
{
|
||||
new Thread(this).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* load data from specifired URL
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
String currLine;
|
||||
try
|
||||
{
|
||||
rdr = new BufferedReader(new InputStreamReader(url.openStream()));
|
||||
|
||||
while ((currLine = rdr.readLine()) != null)
|
||||
{
|
||||
notifyTelegram(currLine.toCharArray());
|
||||
}
|
||||
} catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handlers for TelegramListener List
|
||||
*/
|
||||
|
||||
/**
|
||||
* add a new listener to be notified about new telegrams
|
||||
*
|
||||
* @param newListener - TelegramListener to be added
|
||||
* @return true if adding was OK, otherwise false
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected boolean addTelegramListener(TelegramListener newListener)
|
||||
{
|
||||
return (TelegramListeners.add(newListener));
|
||||
}
|
||||
|
||||
/**
|
||||
* remove a listener to be notified about new telegrams
|
||||
*
|
||||
* @param remListener - TelegramListener to be removed
|
||||
* @return true if adding was OK, otherwise false
|
||||
*/
|
||||
protected boolean removeTelegramListener(TelegramListener remListener)
|
||||
{
|
||||
return (TelegramListeners.remove(remListener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all telegram listeners about new telegram
|
||||
*
|
||||
* @param buffer - telegram buffer
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void notifyTelegram(char[] buffer)
|
||||
{
|
||||
Iterator it = TelegramListeners.iterator();
|
||||
Object currListener;
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
currListener = it.next();
|
||||
if (currListener instanceof TelegramListener)
|
||||
{
|
||||
((TelegramListener) currListener).handleTelegram(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Main routine for testing purpose
|
||||
*/
|
||||
public static void main(String args[])
|
||||
{
|
||||
try
|
||||
{
|
||||
FtpLoader loader = new FtpLoader(args[0]);
|
||||
loader.connect();
|
||||
} catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot;
|
||||
|
||||
/**
|
||||
* Protocol utility tool box
|
||||
*
|
||||
* @author erwin
|
||||
*/
|
||||
public class ProtUtils
|
||||
{
|
||||
|
||||
private static String hexFmt;
|
||||
private static String asciiFmt;
|
||||
|
||||
/**
|
||||
* return HEX:ASCII dump of buffer
|
||||
* in ASCII section all NON ASCII chars are '.'
|
||||
* @param buffer buffer to be dumped
|
||||
* @return String containing HEX:ASCII data of buffer
|
||||
*/
|
||||
public static String hexDumpBuffer(char[] buffer)
|
||||
{
|
||||
hexFmt = "";
|
||||
asciiFmt = "";
|
||||
|
||||
for (int i = 0; i < buffer.length; i++)
|
||||
{
|
||||
hexFmt += String.format("%02X ", (byte) buffer[i]);
|
||||
asciiFmt += String.format("%1s", buffer[i] < 32 || buffer[i] > 127 ? '.' : buffer[i]);
|
||||
}
|
||||
return (hexFmt + " : " + asciiFmt);
|
||||
}
|
||||
|
||||
}
|
||||
+1137
File diff suppressed because it is too large
Load Diff
+359
@@ -0,0 +1,359 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.2" maxVersion="1.2" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,-85,0,0,0,-13"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="panData">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="Center"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="lblPort">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
|
||||
<ComponentRef name="cbPort"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Port"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="5" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="cbPort">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="0"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cbPortItemStateChanged"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lblBaudrate">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
|
||||
<ComponentRef name="cbBaudrate"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Baudrate"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="5" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="cbBaudrate">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="true"/>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="10">
|
||||
<StringItem index="0" value="300"/>
|
||||
<StringItem index="1" value="600"/>
|
||||
<StringItem index="2" value="1200"/>
|
||||
<StringItem index="3" value="2400"/>
|
||||
<StringItem index="4" value="4800"/>
|
||||
<StringItem index="5" value="9600"/>
|
||||
<StringItem index="6" value="19200"/>
|
||||
<StringItem index="7" value="38400"/>
|
||||
<StringItem index="8" value="57600"/>
|
||||
<StringItem index="9" value="115200"/>
|
||||
</StringArray>
|
||||
</Property>
|
||||
<Property name="selectedIndex" type="int" value="5"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="SelectionChanged"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lblDataBits">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
|
||||
<ComponentRef name="cbDataBits"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Data Bits"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="5" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="cbDataBits">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="4">
|
||||
<StringItem index="0" value="5"/>
|
||||
<StringItem index="1" value="6"/>
|
||||
<StringItem index="2" value="7"/>
|
||||
<StringItem index="3" value="8"/>
|
||||
</StringArray>
|
||||
</Property>
|
||||
<Property name="selectedIndex" type="int" value="3"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="SelectionChanged"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lblStopBits">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
|
||||
<ComponentRef name="cbStopBits"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Stop Bits"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="4" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="5" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="cbStopBits">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="3">
|
||||
<StringItem index="0" value="1"/>
|
||||
<StringItem index="1" value="2"/>
|
||||
<StringItem index="2" value="1.5"/>
|
||||
</StringArray>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="SelectionChanged"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="4" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lblParity">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
|
||||
<ComponentRef name="cbParity"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Parity"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="5" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="cbParity">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="5">
|
||||
<StringItem index="0" value="None"/>
|
||||
<StringItem index="1" value="Odd"/>
|
||||
<StringItem index="2" value="Even"/>
|
||||
<StringItem index="3" value="Mark"/>
|
||||
<StringItem index="4" value="Space"/>
|
||||
</StringArray>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="SelectionChanged"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lblHsRx">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Handshake Rx"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="5" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="5" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lblHsTx">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Handshake Tx"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="6" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="5" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="cbProtocolRx">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="3">
|
||||
<StringItem index="0" value="None"/>
|
||||
<StringItem index="1" value="RTS/CTS"/>
|
||||
<StringItem index="2" value="XON/XOFF"/>
|
||||
</StringArray>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="SelectionChanged"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="5" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="cbProtocolTx">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="10" style="0"/>
|
||||
</Property>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="3">
|
||||
<StringItem index="0" value="None"/>
|
||||
<StringItem index="1" value="RTS/CTS"/>
|
||||
<StringItem index="2" value="XON/XOFF"/>
|
||||
</StringArray>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="SelectionChanged"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="6" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="jPanel1">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="South"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
|
||||
<Property name="columns" type="int" value="0"/>
|
||||
<Property name="horizontalGap" type="int" value="1"/>
|
||||
<Property name="rows" type="int" value="1"/>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JToggleButton" name="btnDSR">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="8" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="DSR"/>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JToggleButton" name="btnCTS">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="8" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="CTS"/>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JToggleButton" name="btnCD">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="8" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="CD"/>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JToggleButton" name="btnDTR">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="8" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="DTR"/>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JToggleButton" name="btnRTS">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="8" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="RTS"/>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Extension to native serial selectedPort to allow odd baud rates and 5-Baud operations
|
||||
* especially for automotive usage
|
||||
*
|
||||
* @author erwin
|
||||
*/
|
||||
public class SerialExt
|
||||
{
|
||||
|
||||
private static final Logger log = Logger.getLogger("com.fr3ts0n.prot.ext");
|
||||
|
||||
|
||||
/**
|
||||
* Open serial device
|
||||
*
|
||||
* @param fileName file name of serial device (i.e.: \\.\COMx, /dev/ttySx ...)
|
||||
* @return file descriptor of file device, or -1 if not available
|
||||
*/
|
||||
private static native int openSerial(String fileName);
|
||||
|
||||
/**
|
||||
* Close serial device
|
||||
*
|
||||
* @param fd file descriptor of selectedPort
|
||||
* @return error status of system function (0=success)
|
||||
*/
|
||||
private static native int closeSerial(int fd);
|
||||
|
||||
/**
|
||||
* native interface to
|
||||
* set status of BREAK signal
|
||||
* This is used to create a 5-baud signal for ECU kick-off
|
||||
*
|
||||
* @param fd file descriptor of selectedPort
|
||||
* @param brkStatus desired status of BREAK signal
|
||||
* @return error status of system function (0=success)
|
||||
*/
|
||||
private static native int setBreak(int fd, int brkStatus);
|
||||
|
||||
/**
|
||||
* native interface to
|
||||
* set custom baud rate
|
||||
* Custom baud rates are set by dividing the selectedPort baud base frequency with a
|
||||
* divisor value. Purpose of this function is to allow odd ball ECU baud rates
|
||||
* like 10400 baud etc., which are not supported by regular system calls
|
||||
*
|
||||
* @param fd file descriptor of selectedPort
|
||||
* @param baudRate cusom baud rate to be set
|
||||
* @return error status of system function (0=success)
|
||||
*/
|
||||
private static native int setCustomBaudrate(int fd, int baudrate);
|
||||
|
||||
/**
|
||||
* native interface to
|
||||
* return custom baud rate setting
|
||||
* Custom baud rates are set by dividing the selectedPort baud base frequency with a
|
||||
* divisor value. Purpose of this function is to allow odd ball ECU baud rates
|
||||
* like 10400 baud etc., which are not supported by regular system calls
|
||||
*
|
||||
* @param fd file descriptor of selectedPort
|
||||
* @return custom baud rate setting, or 0 if no custom baud rate was set
|
||||
*/
|
||||
private static native int getCustomBaudrate(int fd);
|
||||
|
||||
/**
|
||||
* receive a character from COM selectedPort
|
||||
*
|
||||
* @param fd file descriptor of selectedPort
|
||||
* @return received character or -1 on receive error
|
||||
*/
|
||||
private static native int receiveChar(int fd);
|
||||
|
||||
/**
|
||||
* send a character from COM selectedPort
|
||||
*
|
||||
* @param fd file descriptor of selectedPort
|
||||
* @param txChar character to be sent
|
||||
* @return error status of system function (0=success)
|
||||
*/
|
||||
private static native int sendChar(int fd, char txChar);
|
||||
|
||||
/** file descriptor of serial selectedPort */
|
||||
public static int serialPortDescriptor = -1;
|
||||
|
||||
static
|
||||
{
|
||||
System.loadLibrary("SerialExt");
|
||||
}
|
||||
|
||||
/**
|
||||
* Open serial device
|
||||
*
|
||||
* @param fileName file name of serial device (i.e.: \\.\COMx, /dev/ttySx ...)
|
||||
* @return file descriptor of file device, or -1 if not available
|
||||
* @throws IOException
|
||||
*/
|
||||
public static int open(String fileName)
|
||||
throws IOException
|
||||
{
|
||||
int result = openSerial(fileName);
|
||||
if (result < 0)
|
||||
{
|
||||
throw new IOException("open");
|
||||
}
|
||||
serialPortDescriptor = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close serial device
|
||||
*
|
||||
* @return error status of serial operation (0=SUCCESS)
|
||||
* @throws IOException
|
||||
*/
|
||||
public static int close()
|
||||
throws IOException
|
||||
{
|
||||
int result = closeSerial(serialPortDescriptor);
|
||||
serialPortDescriptor = -1;
|
||||
if (result != 0)
|
||||
{
|
||||
throw new IOException("close");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set line BREAK status to desired state
|
||||
*
|
||||
* @param newStatus desired BREAK status
|
||||
* @return error status of selectedPort/line setting (0=SUCCESS)
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void setBreak(int newStatus)
|
||||
throws IOException
|
||||
{
|
||||
log.fine(String.format("BREAK %s", newStatus != 0 ? "ON" : "OFF"));
|
||||
int result = setBreak(serialPortDescriptor, newStatus);
|
||||
if (result != 0)
|
||||
{
|
||||
throw new IOException("setBreak");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom baud rate on specified SerialPort
|
||||
*
|
||||
* @param baudrate new baud rate in bps
|
||||
* @return error status of selectedPort/line setting (0=SUCCESS)
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void setCustomBaudrate(int baudrate)
|
||||
throws IOException
|
||||
{
|
||||
log.fine(String.format("Setting custom baudrate %d", baudrate));
|
||||
int result = setCustomBaudrate(serialPortDescriptor, baudrate);
|
||||
if (result != 0)
|
||||
{
|
||||
throw new IOException("setCustomBaudrate");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom baud rate on specified SerialPort
|
||||
*
|
||||
* @return error status of selectedPort/line setting (0=SUCCESS)
|
||||
* @throws IOException
|
||||
*/
|
||||
public static int getCustomBaudrate()
|
||||
throws IOException
|
||||
{
|
||||
int result = getCustomBaudrate(serialPortDescriptor);
|
||||
log.fine(String.format("getting custom baudrate %d", result));
|
||||
if (result <= 0)
|
||||
{
|
||||
throw new IOException("getCustomBaudrate");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* receive a character from COM selectedPort
|
||||
*
|
||||
* @return received character or -1 on receive error
|
||||
*/
|
||||
public static int receiveChar()
|
||||
throws IOException
|
||||
{
|
||||
log.finer("waiting for RX char");
|
||||
int result = receiveChar(serialPortDescriptor);
|
||||
if (result < 0)
|
||||
{
|
||||
throw new IOException(String.format("receiveChar:%02X", result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* send a character to COM selectedPort
|
||||
*
|
||||
* @param txChar character to be sent
|
||||
* @return received character or -1 on send error
|
||||
*/
|
||||
public static int sendChar(byte txChar)
|
||||
throws IOException
|
||||
{
|
||||
log.finer(String.format("sending char:%02X", (byte) txChar));
|
||||
int result = sendChar(serialPortDescriptor, (char) txChar);
|
||||
if (result < 0)
|
||||
{
|
||||
throw new IOException(String.format("sendChar:%d", result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* send characters to COM selectedPort
|
||||
*
|
||||
* @param txBytes characters to be sent
|
||||
* @return received character or -1 on send error
|
||||
*/
|
||||
public static int write(byte[] txBytes)
|
||||
throws IOException
|
||||
{
|
||||
int result = 0;
|
||||
for (int i = 0; i < txBytes.length; i++)
|
||||
result |= sendChar(txBytes[i]);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 Foundationpe; either version 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot;
|
||||
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.Vector;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* Protocol I/O stream handler
|
||||
*
|
||||
* @author erwin
|
||||
*/
|
||||
public class StreamHandler implements TelegramWriter, Runnable
|
||||
{
|
||||
private static final Logger log = Logger.getLogger("stream");
|
||||
private InputStream in;
|
||||
private BufferedWriter out;
|
||||
|
||||
private TelegramListener messageHandler;
|
||||
// current receive message
|
||||
private String message = "";
|
||||
|
||||
public StreamHandler()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct new StreamHandler using specified input and output stream
|
||||
*
|
||||
* @param inStream stream for incoming messages
|
||||
* @param outStream stream for outgoing messages
|
||||
*/
|
||||
public StreamHandler(InputStream inStream, OutputStream outStream)
|
||||
{
|
||||
setStreams(inStream, outStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the input and output stream
|
||||
*
|
||||
* @param inStream stream for incoming messages
|
||||
* @param outStream stream for outgoing messages
|
||||
*/
|
||||
public void setStreams(InputStream inStream, OutputStream outStream)
|
||||
{
|
||||
in = inStream;
|
||||
/* Output uses BufferedWriter with buffer size 1 byte to trigger
|
||||
flushing on every outgoing byte [$Fix #AndrOBD-27] */
|
||||
out = new BufferedWriter(new OutputStreamWriter(outStream), 1);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.fr3ts0n.prot.TelegramWriter#writeTelegram(char[])
|
||||
*/
|
||||
@Override
|
||||
public int writeTelegram(char[] buffer)
|
||||
{
|
||||
return (writeTelegram(buffer, 0, null));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.fr3ts0n.prot.TelegramWriter#writeTelegram(char[], int, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int writeTelegram(final char[] buffer, int type, Object id)
|
||||
{
|
||||
int result = buffer.length;
|
||||
|
||||
// Send data threaded to de-couple from main thread
|
||||
new Thread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
String msg = new String(buffer);
|
||||
msg += "\r";
|
||||
|
||||
log.finer(this.toString() + " TX:"
|
||||
+ ProtUtils.hexDumpBuffer(msg.toCharArray()));
|
||||
|
||||
out.write(msg.toCharArray());
|
||||
out.flush();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.severe("TX error:'"
|
||||
+ ProtUtils.hexDumpBuffer(buffer) + "':"
|
||||
+ ex.getStackTrace());
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
return (result);
|
||||
}
|
||||
|
||||
/**
|
||||
* process incoming character
|
||||
*
|
||||
* @param chr the received char
|
||||
*/
|
||||
private void processRxChar(int chr)
|
||||
{
|
||||
// process incoming data
|
||||
log.finer(this.toString() + " RX: '"
|
||||
+ String.format("%02X : %1c", (byte) chr, chr < 32 ? '.' : chr)
|
||||
+ "'");
|
||||
|
||||
switch (chr)
|
||||
{
|
||||
// ignore special characters
|
||||
case 32:
|
||||
break;
|
||||
|
||||
// trigger message handling for new request
|
||||
case '>':
|
||||
message += (char) chr;
|
||||
// trigger message handling
|
||||
case 10:
|
||||
case 13:
|
||||
try
|
||||
{
|
||||
if (messageHandler != null && !message.isEmpty())
|
||||
{ messageHandler.handleTelegram(message.toCharArray()); }
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.log(Level.WARNING, "handleTelegram", ex);
|
||||
}
|
||||
message = "";
|
||||
break;
|
||||
|
||||
default:
|
||||
message += (char) chr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* start the thread
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("fallthrough")
|
||||
public void run()
|
||||
{
|
||||
int chr;
|
||||
log.info("RX Thread started");
|
||||
try
|
||||
{
|
||||
// loop until stream closed / invalid
|
||||
while (true)
|
||||
{
|
||||
// if no data available, then wait for it
|
||||
if (in.available() > 0)
|
||||
{
|
||||
// otherwise read- and process ...
|
||||
|
||||
// Is end of stream reached?
|
||||
if ((chr = in.read()) > 0)
|
||||
{
|
||||
// process incoming data
|
||||
processRxChar(chr);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.warning(this.toString() + " RX: End of stream!");
|
||||
// stream finished - break loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// wait 1 ms for incoming data
|
||||
Thread.sleep(1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.log(Level.WARNING, "RX error", ex);
|
||||
}
|
||||
|
||||
log.info("RX Thread stopped");
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for property messageHandler.
|
||||
*
|
||||
* @return Value of property messageHandler.
|
||||
*/
|
||||
public TelegramListener getMessageHandler()
|
||||
{
|
||||
return messageHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property messageHandler.
|
||||
*
|
||||
* @param messageHandler New value of property messageHandler.
|
||||
*/
|
||||
public void setMessageHandler(TelegramListener messageHandler)
|
||||
{
|
||||
this.messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility field used by event firing mechanism.
|
||||
*/
|
||||
private Vector<PropertyChangeListener> listenerList = null;
|
||||
|
||||
/**
|
||||
* Registers PropertyChangeListener to receive events.
|
||||
*
|
||||
* @param listener The listener to register.
|
||||
*/
|
||||
public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
|
||||
{
|
||||
if (listenerList == null)
|
||||
{
|
||||
listenerList = new Vector<PropertyChangeListener>();
|
||||
}
|
||||
listenerList.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes PropertyChangeListener from the list of listeners.
|
||||
*
|
||||
* @param listener The listener to remove.
|
||||
*/
|
||||
public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
|
||||
{
|
||||
listenerList.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all registered listeners about the event.
|
||||
*
|
||||
* @param event The event to be fired
|
||||
*/
|
||||
protected void firePropertyChange(PropertyChangeEvent event)
|
||||
{
|
||||
|
||||
if (listenerList == null) { return; }
|
||||
PropertyChangeListener listener;
|
||||
for (PropertyChangeListener aListenerList : listenerList)
|
||||
{
|
||||
listener = aListenerList;
|
||||
listener.propertyChange(event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
* TelegramListener
|
||||
* Interface to handle incoming protocol Telegrams
|
||||
*/
|
||||
public interface TelegramListener extends EventListener
|
||||
{
|
||||
/**
|
||||
* handle incoming protocol telegram
|
||||
*
|
||||
* @param buffer - telegram buffer
|
||||
* @return number of listeners notified
|
||||
*/
|
||||
int handleTelegram(char[] buffer);
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* TelegramSender
|
||||
* list of telegram writers
|
||||
* (handlers for outgoing telegrams)
|
||||
*
|
||||
* @author $Author: erwin $
|
||||
* @version $Id: TelegramSender.java,v 1.12 2010-02-23 21:36:27 erwin Exp $
|
||||
*/
|
||||
public class TelegramSender
|
||||
{
|
||||
/**
|
||||
* Handlers for TelegramWriter List
|
||||
*/
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final
|
||||
Vector telegramWriters = new Vector();
|
||||
|
||||
/**
|
||||
* add a new Writer to be notified about new telegrams
|
||||
*
|
||||
* @param newWriter - TelegramWriter to be added
|
||||
* @return true if adding was OK, otherwise false
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean addTelegramWriter(TelegramWriter newWriter)
|
||||
{
|
||||
return (telegramWriters.add(newWriter));
|
||||
}
|
||||
|
||||
/**
|
||||
* remove a Writer to be notified about new telegrams
|
||||
*
|
||||
* @param remWriter - TelegramWriter to be removed
|
||||
* @return true if adding was OK, otherwise false
|
||||
*/
|
||||
public boolean removeTelegramWriter(TelegramWriter remWriter)
|
||||
{
|
||||
return (telegramWriters.remove(remWriter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all telegram Writers about new telegram
|
||||
*
|
||||
* @param buffer - telegram buffer
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void sendTelegram(char[] buffer, int type, Object id)
|
||||
{
|
||||
Iterator it = telegramWriters.iterator();
|
||||
Object currWriter;
|
||||
|
||||
ProtoHeader.log.finer(this.toString() + " TX:" + ProtUtils.hexDumpBuffer(buffer));
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
currWriter = it.next();
|
||||
if (currWriter instanceof TelegramWriter)
|
||||
{
|
||||
((TelegramWriter) currWriter).writeTelegram(buffer, type, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all telegram Writers about new telegram
|
||||
*
|
||||
* @param buffer - telegram buffer
|
||||
*/
|
||||
public void sendTelegram(char[] buffer)
|
||||
{
|
||||
sendTelegram(buffer, 0, null);
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
* TelegramWriter
|
||||
* Interface to handle outgoing protocol Telegrams
|
||||
*/
|
||||
public interface TelegramWriter extends EventListener
|
||||
{
|
||||
/**
|
||||
* handle outgoing protocol telegram
|
||||
*
|
||||
* @param buffer - telegram buffer
|
||||
* @return number of bytes sent
|
||||
*/
|
||||
int writeTelegram(char[] buffer);
|
||||
|
||||
/**
|
||||
* handle outgoing protocol telegram
|
||||
*
|
||||
* @param buffer - telegram buffer
|
||||
* @param type telegram type (numeric ID)
|
||||
* @param id unique telegram ID (Sequence number) may be null to generate automatic
|
||||
* @return number of bytes sent
|
||||
*/
|
||||
int writeTelegram(char[] buffer, int type, Object id);
|
||||
|
||||
}
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Wrapper work class to create InputStream from a Datagram Socket
|
||||
*
|
||||
* @author $Author: erwin $
|
||||
*/
|
||||
class UdpInputStream extends PipedInputStream
|
||||
{
|
||||
|
||||
/** receive buffer */
|
||||
private final char[] buffer = new char[16384];
|
||||
/** receiving datagram packet */
|
||||
private DatagramPacket packet;
|
||||
/** Datagram socket object to be listened to */
|
||||
private DatagramSocket socket = null;
|
||||
/** the pipe which connects socket output to buffer input */
|
||||
private PipedOutputStream out = null;
|
||||
/** the worker thread to read the socket */
|
||||
private Thread readerThread = null;
|
||||
/** Logging Object */
|
||||
private static final Logger log = Logger.getLogger("STREAM");
|
||||
private long charsReceived = 0;
|
||||
private long startTime = 0;
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
private UdpInputStream()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* construct with existing DatagramSocket
|
||||
*/
|
||||
public UdpInputStream(DatagramSocket newSocket)
|
||||
{
|
||||
this();
|
||||
setSocket(newSocket);
|
||||
}
|
||||
|
||||
/**
|
||||
* get current datagram socket
|
||||
*/
|
||||
public DatagramSocket getSocket()
|
||||
{
|
||||
return (socket);
|
||||
}
|
||||
|
||||
private void closeItAll()
|
||||
throws IOException
|
||||
{
|
||||
// terminate and destroy current reader thread (if available)
|
||||
if (readerThread != null)
|
||||
{
|
||||
readerThread.interrupt();
|
||||
/*
|
||||
try
|
||||
{
|
||||
readerThread.join();
|
||||
}
|
||||
catch(InterruptedException e)
|
||||
{
|
||||
log.severe(e);
|
||||
}
|
||||
*/
|
||||
}
|
||||
if (socket != null)
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
if (out != null)
|
||||
{
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* close the UdpInputStream and release all associated resources
|
||||
*/
|
||||
public void close()
|
||||
throws IOException
|
||||
{
|
||||
log.info("Closing UdpInputStream");
|
||||
closeItAll();
|
||||
super.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* set datagram socket for data reading
|
||||
*/
|
||||
private void setSocket(DatagramSocket newSocket)
|
||||
{
|
||||
// only do something if the socket really changes
|
||||
if (newSocket != socket)
|
||||
{
|
||||
try
|
||||
{
|
||||
closeItAll();
|
||||
log.info("Opening UdpInputStream");
|
||||
out = new PipedOutputStream(this);
|
||||
// set socket to the new one
|
||||
socket = newSocket;
|
||||
// create a new reader thread ...
|
||||
readerThread = new Thread()
|
||||
{
|
||||
|
||||
public void run()
|
||||
{
|
||||
log.info("UdpReader started");
|
||||
try
|
||||
{
|
||||
while (!isInterrupted())
|
||||
{
|
||||
packet.setLength(buffer.length);
|
||||
socket.receive(packet);
|
||||
charsReceived += packet.getLength();
|
||||
out.write(packet.getData(), 0, packet.getLength());
|
||||
log.fine("RX:" + new String(packet.getData()));
|
||||
}
|
||||
} catch (IOException e)
|
||||
{
|
||||
log.severe(e.toString());
|
||||
}
|
||||
log.info("UdpReader finished");
|
||||
}
|
||||
};
|
||||
// mark socket staring time
|
||||
startTime = System.currentTimeMillis();
|
||||
// set number of chars received to zero
|
||||
charsReceived = 0;
|
||||
// and start listening ...
|
||||
readerThread.start();
|
||||
} catch (IOException e)
|
||||
{
|
||||
log.severe(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* show receive statistics on selectedPort close
|
||||
* this is activated for testing only
|
||||
*
|
||||
*/
|
||||
/*
|
||||
public void close()
|
||||
{
|
||||
try
|
||||
{
|
||||
long duration = (System.currentTimeMillis()-startTime)/1000;
|
||||
System.out.println( "RX: "+String.valueOf(charsReceived)
|
||||
+" Time: "+String.valueOf(duration)
|
||||
+" Thpt: "+String.valueOf(charsReceived/duration));
|
||||
super.close();
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
log.severe(e);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,723 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot.gui;
|
||||
|
||||
|
||||
import com.fr3ts0n.prot.ProtUtils;
|
||||
import com.fr3ts0n.prot.SerialExt;
|
||||
import com.fr3ts0n.prot.TelegramWriter;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.Vector;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.Timer;
|
||||
|
||||
/**
|
||||
* Communication handler for KL-Adaptor
|
||||
*
|
||||
* @author erwin
|
||||
*/
|
||||
public class KLHandler extends SerialHandler
|
||||
implements TelegramWriter
|
||||
{
|
||||
|
||||
/**
|
||||
* Status of package transmission / reception - to determine if we are
|
||||
* processing data, or complements
|
||||
*/
|
||||
public enum PacketStatus
|
||||
{
|
||||
ECHO,
|
||||
COMPLEMENT,
|
||||
DATA,
|
||||
}
|
||||
|
||||
// baud rates supported by this adapter
|
||||
private final int[] baudRates =
|
||||
{
|
||||
10400, 9600, 4800, 2400
|
||||
};
|
||||
// synch char
|
||||
private static final char SYNC_CHAR = 0x55;
|
||||
// current packet status
|
||||
private PacketStatus pktStat = PacketStatus.COMPLEMENT;
|
||||
// telegram block counter
|
||||
private char blockCounter = 0;
|
||||
/* current address in use */
|
||||
private int currAddress = 0; // (see ecuadr.csv)
|
||||
/** current baud rate */
|
||||
private int currBaudRate = 0;
|
||||
// last byte sent;
|
||||
private char lastTxChar = 0;
|
||||
/** Queue of telegrams to be sent */
|
||||
private final Vector<char[]> txTelegramQueue = new Vector<char[]>();
|
||||
/** current telegram to be sent */
|
||||
private char[] currTxTgm = {};
|
||||
/** current position of byte to be sent from within currTxTgm */
|
||||
private int currTxCharPos = 0;
|
||||
|
||||
/**
|
||||
* Protocol timing parameters
|
||||
*/
|
||||
/** time of last reception */
|
||||
private long lastRxTime = 0;
|
||||
/** number of bits to pause (parameter fo calculation of interByteTime) */
|
||||
private static final int numBitsPause = 0;
|
||||
/** time [nanoseconds] to wait for sending next byte */
|
||||
private long interByteTime = 0; // [ns]
|
||||
|
||||
/** time [ms] to detect communication timeout */
|
||||
private final int commTimeoutTime = 2000; // [ms]
|
||||
/** Timer to detect communication timeout */
|
||||
private Timer commTimer;
|
||||
|
||||
/** Handler for communication Timeout */
|
||||
private final ActionListener commTimeoutHandler = new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0)
|
||||
{
|
||||
log.warning("CommTimeout");
|
||||
close();
|
||||
setProtStat(ProtStatus.TIMEOUT);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public KLHandler()
|
||||
{
|
||||
// set the logger object
|
||||
log = Logger.getLogger("com.fr3ts0n.prot.kl");
|
||||
|
||||
commTimer = new Timer(commTimeoutTime, commTimeoutHandler);
|
||||
commTimer.setInitialDelay(commTimeoutTime);
|
||||
commTimer.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* construct with connecting to device
|
||||
*
|
||||
* @param device device to connect
|
||||
*/
|
||||
public KLHandler(String device)
|
||||
{
|
||||
try
|
||||
{
|
||||
setDeviceName(device);
|
||||
} catch (Exception ex)
|
||||
{
|
||||
log.log(Level.SEVERE,"",ex);
|
||||
}
|
||||
commTimer = new Timer(commTimeoutTime, commTimeoutHandler);
|
||||
commTimer.setInitialDelay(commTimeoutTime);
|
||||
commTimer.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currBaudRate
|
||||
*/
|
||||
// current baud rate in use
|
||||
private int getCurrBaudRate()
|
||||
{
|
||||
return currBaudRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param currBaudRate the currBaudRate to set
|
||||
*/
|
||||
private void setCurrBaudRate(int currBaudRate)
|
||||
{
|
||||
firePropertyChange(new PropertyChangeEvent(this, "baud", this.currBaudRate, currBaudRate));
|
||||
this.currBaudRate = currBaudRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currAddress
|
||||
*/
|
||||
private int getCurrAddress()
|
||||
{
|
||||
return currAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param currAddress the currAddress to set
|
||||
*/
|
||||
private void setCurrAddress(int currAddress)
|
||||
{
|
||||
this.currAddress = currAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* close communication port
|
||||
*/
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
txTelegramQueue.clear();
|
||||
if (commTimer != null)
|
||||
{
|
||||
commTimer.stop();
|
||||
}
|
||||
super.close();
|
||||
// set shutdown status
|
||||
setProtStat(ProtStatus.OFFLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* add new listener for communication timeout
|
||||
*
|
||||
* @param listener new timeout listener
|
||||
*/
|
||||
public void addTimeoutListener(ActionListener listener)
|
||||
{
|
||||
commTimer.addActionListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* set port speed to specified baud rate
|
||||
*
|
||||
* @param newBaudRate new baud rate to be set
|
||||
*/
|
||||
private void setCustomBaudRate(int newBaudRate)
|
||||
{
|
||||
try
|
||||
{
|
||||
SerialExt.setCustomBaudrate(newBaudRate);
|
||||
} catch (Exception e)
|
||||
{
|
||||
log.log(Level.SEVERE,"Set custom baudrate", e);
|
||||
}
|
||||
|
||||
// show baudrate setting as debug output
|
||||
try
|
||||
{
|
||||
log.fine(String.format("Baudrate:%d/%d",
|
||||
SerialExt.getCustomBaudrate(),
|
||||
newBaudRate));
|
||||
} catch (Exception e)
|
||||
{
|
||||
log.log(Level.SEVERE,null, e);
|
||||
}
|
||||
// calculate new interByteTime (1M ns *numBits / bps)
|
||||
interByteTime = 1000000000 * numBitsPause / newBaudRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* send a single bit with 5 baud bit width
|
||||
*
|
||||
* @param bitValue
|
||||
*/
|
||||
private void sendBit5Baud(boolean bitValue)
|
||||
throws IOException
|
||||
{
|
||||
// set line status
|
||||
SerialExt.setBreak(bitValue ? 0 : 1);
|
||||
// RTS line follows inverse data bit ...
|
||||
// device.setRTS(!bitValue);
|
||||
// and wait a single bit time
|
||||
try
|
||||
{
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException e)
|
||||
{
|
||||
log.log(Level.SEVERE,null, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* send a byte with 5 baud line speed
|
||||
* this version sends out timed line break bits w/o changing the nominal
|
||||
* baud rate
|
||||
*
|
||||
* @param address CU to be addressed
|
||||
*/
|
||||
private void sendByte5Baud(int address)
|
||||
throws IOException
|
||||
{
|
||||
long start = System.currentTimeMillis();
|
||||
// ensure stop bit
|
||||
// sendBit5Baud(true);
|
||||
// start sending
|
||||
// device.setDTR(false);
|
||||
// start bit
|
||||
sendBit5Baud(false);
|
||||
// 8 data bits, LSB first
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
sendBit5Baud((address & (1 << i)) != 0);
|
||||
}
|
||||
// stop bit
|
||||
sendBit5Baud(true);
|
||||
// finish sending
|
||||
// device.setDTR(true);
|
||||
log.fine(String.format("TX-5Baud:%02X finished after %dms", address, System.currentTimeMillis() - start));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize communication by sending specified ECU address with 5 baud
|
||||
*
|
||||
* @param address ECU to be addressed
|
||||
* @return initialization status (0=OK, -1=Error)
|
||||
*/
|
||||
private void send5Baud(int address)
|
||||
throws IOException
|
||||
{
|
||||
int result = 0;
|
||||
setProtStat(ProtStatus.CONNECTING);
|
||||
|
||||
sendByte5Baud(address);
|
||||
message = "";
|
||||
// return status
|
||||
}
|
||||
|
||||
/**
|
||||
* send specified char to output device
|
||||
*
|
||||
* @param txByte byte to be sent
|
||||
* @param rememberTx remember last TX character
|
||||
*/
|
||||
private void writeChar(char txByte, boolean rememberTx)
|
||||
{
|
||||
try
|
||||
{
|
||||
log.fine("TX:" + String.format("%02X", (byte) txByte));
|
||||
|
||||
// if this byte should be remembered as TX byte, do it
|
||||
if (rememberTx)
|
||||
{
|
||||
lastTxChar = txByte;
|
||||
}
|
||||
wrtr.write((int) txByte);
|
||||
pktStat = PacketStatus.ECHO;
|
||||
} catch (Exception ex)
|
||||
{
|
||||
log.log(Level.SEVERE,this.toString(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* confirm reception of last byte by sending complement of it back
|
||||
*
|
||||
* @param lastByte last received byte
|
||||
*/
|
||||
private void confirmByte(char lastByte)
|
||||
{
|
||||
// change to complement status ...
|
||||
pktStat = PacketStatus.COMPLEMENT;
|
||||
writeChar((char) ~lastByte, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for receiving chars from serial port
|
||||
*/
|
||||
class RxThread extends Thread
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
int chr;
|
||||
log.fine("Reader Thread started");
|
||||
while (rdr != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
chr = rdr.read();
|
||||
log.fine(String.format("RX:%02X : %c\t%s\t%s", chr, chr < 32 || chr > 127 ? '.' : chr,
|
||||
getProtStat(), pktStat));
|
||||
switch (getProtStat())
|
||||
{
|
||||
case RECEIVING:
|
||||
// restart comm timeout timer
|
||||
commTimer.restart();
|
||||
switch (pktStat)
|
||||
{
|
||||
case ECHO:
|
||||
lastTxChar = 0;
|
||||
// ignore the echo of sent complement
|
||||
pktStat = PacketStatus.DATA;
|
||||
break;
|
||||
|
||||
case COMPLEMENT:
|
||||
// ignore the echo of sent complement
|
||||
pktStat = PacketStatus.DATA;
|
||||
break;
|
||||
|
||||
case DATA:
|
||||
// remember time of last RX
|
||||
lastRxTime = System.currentTimeMillis();
|
||||
// add char to current RX message
|
||||
message += (char) chr;
|
||||
// do we have received a complete package?
|
||||
if (chr == 0x03 && message.length() > message.charAt(0))
|
||||
{
|
||||
//
|
||||
// package is complete
|
||||
//
|
||||
log.fine("RX:" + ProtUtils.hexDumpBuffer(message.toCharArray()));
|
||||
// update block counter with the received one
|
||||
blockCounter = message.charAt(1);
|
||||
// notify protocol handler of the new package
|
||||
messageHandler.handleTelegram(message.toCharArray());
|
||||
// clear the message
|
||||
message = "";
|
||||
// and change to send status
|
||||
setProtStat(ProtStatus.SENDING);
|
||||
sendNextByte();
|
||||
} else
|
||||
{
|
||||
//
|
||||
// package is still incomplete
|
||||
//
|
||||
|
||||
// and send out confirmation for received byte
|
||||
confirmByte((char) chr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SENDING:
|
||||
{
|
||||
switch (pktStat)
|
||||
{
|
||||
case ECHO:
|
||||
case DATA:
|
||||
// ignore the echo of sent data
|
||||
pktStat = PacketStatus.COMPLEMENT;
|
||||
break;
|
||||
|
||||
case COMPLEMENT:
|
||||
// restart comm timeout timer
|
||||
commTimer.restart();
|
||||
if (chr == (~lastTxChar & 0xFF))
|
||||
{
|
||||
pktStat = PacketStatus.DATA;
|
||||
sendNextByte();
|
||||
} else
|
||||
{
|
||||
log.log(Level.SEVERE,String.format("Wrong complement:%02X, expected:%02X", chr, ~lastTxChar));
|
||||
// TODO: handle communication error
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CONNECTING:
|
||||
{
|
||||
// if we receive the echo of the init byte, sending is done
|
||||
if (chr == lastTxChar)
|
||||
{
|
||||
// ignore echo byte
|
||||
} else
|
||||
{
|
||||
if (chr == SYNC_CHAR)
|
||||
{
|
||||
message = "";
|
||||
}
|
||||
// otherwise collect sync and key bytes
|
||||
message += (char) chr;
|
||||
// did we receive all INIT bytes (SYNC_CHAR, KW-lo, KW-hi)?
|
||||
if (message.length() > 2 && message.charAt(0) == SYNC_CHAR)
|
||||
{
|
||||
// notify protocol handler of initialization message to get keyword etc
|
||||
// messageHandler.handleTelegram(message.toCharArray());
|
||||
message = "";
|
||||
// Initialization is finished, change to status RECEIVING
|
||||
setProtStat(ProtStatus.RECEIVING);
|
||||
// confirm the last received byte
|
||||
confirmByte((char) chr);
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
log.log(Level.SEVERE,ex.toString());
|
||||
try
|
||||
{
|
||||
sleep(1000);
|
||||
} catch (InterruptedException ex1)
|
||||
{
|
||||
log.log(Level.SEVERE,ex1.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
log.warning("Reader Tread finished");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write a telegram to serial port
|
||||
* implementation of SerialHandler
|
||||
*/
|
||||
@Override
|
||||
public int writeTelegram(char[] buffer)
|
||||
{
|
||||
return writeTelegram(buffer, 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* write a telegram to serial port
|
||||
* implementation of SerialHandler
|
||||
*/
|
||||
@Override
|
||||
public int writeTelegram(char[] buffer, int type, Object id)
|
||||
{
|
||||
return enqueueTelegram(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* start the serial handler
|
||||
* Implementation for compatibility
|
||||
*/
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
// start the receive thread
|
||||
new Thread()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
init5Baud(getCurrAddress());
|
||||
}
|
||||
}.start();
|
||||
new RxThread().start();
|
||||
}
|
||||
|
||||
/**
|
||||
* send next available byte
|
||||
*
|
||||
* @return error status of dequeue and send operation
|
||||
*/
|
||||
private void sendNextByte()
|
||||
{
|
||||
int result = 0;
|
||||
// wait for slow ECUs
|
||||
try
|
||||
{
|
||||
// calculate remaining time to wait (Sytem time resolution sucks...)
|
||||
long tDiff = interByteTime - ((System.currentTimeMillis() - lastRxTime) * 1000000000);
|
||||
if (tDiff > 0)
|
||||
{
|
||||
log.fine("TX: waiting " + tDiff + " ns");
|
||||
Thread.sleep(tDiff / 1000000L, (int) (tDiff % 1000000L));
|
||||
}
|
||||
} catch (InterruptedException ex)
|
||||
{
|
||||
log.log(Level.SEVERE,"wait: " + ex.toString());
|
||||
}
|
||||
|
||||
// if we have to dequeue a new telegram ...
|
||||
if (currTxCharPos >= currTxTgm.length)
|
||||
{
|
||||
// ... then try to dequeue one
|
||||
result = dequeueTelegram();
|
||||
}
|
||||
// if there is something to send, send the next char
|
||||
if (result == 0)
|
||||
{
|
||||
writeChar(currTxTgm[currTxCharPos++], true);
|
||||
if (currTxCharPos >= currTxTgm.length)
|
||||
{
|
||||
setProtStat(ProtStatus.RECEIVING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* enqueue a telegram to be sent
|
||||
*
|
||||
* @param buffer telegram to be sent
|
||||
* @return error status of enqueue
|
||||
*/
|
||||
private int enqueueTelegram(char[] buffer)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
// if the queue is empty and current message is completely sent
|
||||
if (txTelegramQueue.size() == 0 && currTxCharPos >= currTxTgm.length)
|
||||
{
|
||||
// make buffer the current telegram
|
||||
currTxTgm = buffer;
|
||||
currTxCharPos = 0;
|
||||
} else
|
||||
{
|
||||
// otherwise put it into queue
|
||||
result = txTelegramQueue.add(buffer) ? 0 : -1;
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a acknowledge telegram for current protocol state
|
||||
*
|
||||
* @return ACK telegram with current block counter
|
||||
*/
|
||||
private char[] getAckTelegram()
|
||||
{
|
||||
return new char[]
|
||||
{
|
||||
0x03, ++blockCounter, 0x09, 0x03
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* dequeue next telegram to be sent
|
||||
*
|
||||
* @return error code of dequeue operation
|
||||
*/
|
||||
private int dequeueTelegram()
|
||||
{
|
||||
int result;
|
||||
// is there any telegram in the queue?
|
||||
if (txTelegramQueue.size() > 0)
|
||||
{
|
||||
// ... then dequeue it
|
||||
currTxTgm = txTelegramQueue.remove(0);
|
||||
// if necessary, adjust block counter
|
||||
if (currTxTgm[1] != (blockCounter + 1))
|
||||
{
|
||||
log.info(String.format("MsgCounter adjusted:%02x->%02x", (int) currTxTgm[1], (int) blockCounter + 1));
|
||||
currTxTgm[1] = ++blockCounter;
|
||||
}
|
||||
// ... and set byte pointer to start of telegram
|
||||
currTxCharPos = 0;
|
||||
result = 0;
|
||||
} else
|
||||
{
|
||||
// nothing in the pipe, so just send an acknowledge telegram
|
||||
currTxTgm = getAckTelegram();
|
||||
currTxCharPos = 0;
|
||||
result = 0;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize communication by sending specified ECU address with 5 baud
|
||||
*
|
||||
* @param address ECU to be addressed
|
||||
* @return baud rate of successful connection, or 0 if no connection could be established
|
||||
*/
|
||||
public synchronized int init5Baud(int address)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
// set current address
|
||||
setCurrAddress(address);
|
||||
try
|
||||
{
|
||||
setDeviceName(deviceName);
|
||||
// loop through all known baud rates
|
||||
for (int i = 0; i < baudRates.length; i++)
|
||||
{
|
||||
log.info(String.format("Init Device:%s Address:%02x, Speed:%d", deviceName, address, baudRates[i]));
|
||||
// set communication baud rate
|
||||
setCustomBaudRate(baudRates[i]);
|
||||
// remember current baud rate
|
||||
setCurrBaudRate(baudRates[i]);
|
||||
setProtStat(ProtStatus.CONNECTING);
|
||||
// init communication with 5 baud address
|
||||
send5Baud(address);
|
||||
try
|
||||
{
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e)
|
||||
{
|
||||
log.log(Level.SEVERE,"Sleep", e);
|
||||
}
|
||||
// if we received an answer, we are not initializing any more
|
||||
if (getProtStat() != ProtStatus.CONNECTING)
|
||||
{
|
||||
log.info(String.format("Init OK Device:%s Address:%02x, Speed:%d", deviceName, address, baudRates[i]));
|
||||
// set return value
|
||||
result = getCurrBaudRate();
|
||||
// start communication timer
|
||||
commTimer.restart();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == 0)
|
||||
{
|
||||
log.warning(String.format("Init Timeout Device:%s Address:%02x", deviceName, address));
|
||||
close();
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
log.log(Level.SEVERE,deviceName + ": " + ex.toString());
|
||||
close();
|
||||
setProtStat(ProtStatus.ERROR);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
// remember current baud rate
|
||||
setCurrBaudRate(result);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The main routine for testing
|
||||
*
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String args[])
|
||||
{
|
||||
// set default parameters
|
||||
int address = 0x01;
|
||||
String device = "/dev/ttyUSB0";
|
||||
// update parameters by command line params
|
||||
if (args.length > 0)
|
||||
{
|
||||
device = args[0];
|
||||
}
|
||||
if (args.length > 1)
|
||||
{
|
||||
address = Integer.parseInt(args[1], 16);
|
||||
}
|
||||
|
||||
KLHandler hdlr = new KLHandler(device);
|
||||
|
||||
hdlr.init5Baud(address);
|
||||
|
||||
// wait until we are shutting down
|
||||
while (hdlr.getProtStat() != ProtStatus.CONNECTING
|
||||
&& hdlr.getProtStat() != ProtStatus.OFFLINE)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
hdlr.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,732 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot.gui;
|
||||
|
||||
|
||||
import com.fr3ts0n.prot.ProtUtils;
|
||||
import com.fr3ts0n.prot.SerialExt;
|
||||
import com.fr3ts0n.prot.TelegramWriter;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.Vector;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.Timer;
|
||||
|
||||
/**
|
||||
* Communication handler for KL-Adaptor
|
||||
*
|
||||
* @author erwin
|
||||
*/
|
||||
public class KLHandlerGeneric extends SerialHandlerGeneric
|
||||
implements TelegramWriter
|
||||
{
|
||||
|
||||
/**
|
||||
* Status of package transmission / reception - to determine if we are
|
||||
* processing data, or complements
|
||||
*/
|
||||
public enum PacketStatus
|
||||
{
|
||||
ECHO,
|
||||
COMPLEMENT,
|
||||
DATA,
|
||||
}
|
||||
|
||||
// baud rates supported by this adapter
|
||||
private final int[] baudRates =
|
||||
{
|
||||
10400, 9600, 4800, 2400
|
||||
};
|
||||
// synch char
|
||||
private static final char SYNC_CHAR = 0x55;
|
||||
// current packet status
|
||||
private PacketStatus pktStat = PacketStatus.COMPLEMENT;
|
||||
// telegram block counter
|
||||
private char blockCounter = 0;
|
||||
/* current address in use */
|
||||
private int currAddress = 0; // (see ecuadr.csv)
|
||||
/** current baud rate */
|
||||
private int currBaudRate = 0;
|
||||
// last byte sent;
|
||||
private char lastTxChar = 0;
|
||||
/** Queue of telegrams to be sent */
|
||||
private final Vector<char[]> txTelegramQueue = new Vector<char[]>();
|
||||
/** current telegram to be sent */
|
||||
private char[] currTxTgm = {};
|
||||
/** current position of byte to be sent from within currTxTgm */
|
||||
private int currTxCharPos = 0;
|
||||
|
||||
/**
|
||||
* Protocol timing parameters
|
||||
*/
|
||||
/** time of last reception */
|
||||
private long lastRxTime = 0;
|
||||
/** time [ms] to detect communication timeout */
|
||||
private static final int commTimeoutTime = 2000; // [ms]
|
||||
/** number of bits to pause (parameter fo calculation of interByteTime) */
|
||||
private static final int numBitsPause = 0;
|
||||
/** time [nanoseconds] to wait for sending next byte */
|
||||
private long interByteTime = 0; // [ns]
|
||||
|
||||
/** Timer to detect communication timeout */
|
||||
private Timer commTimer;
|
||||
|
||||
/** Handler for communication Timeout */
|
||||
private final ActionListener commTimeoutHandler = new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0)
|
||||
{
|
||||
log.warning("CommTimeout");
|
||||
close();
|
||||
setProtStat(ProtStatus.TIMEOUT);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public KLHandlerGeneric()
|
||||
{
|
||||
// set the logger object
|
||||
log = Logger.getLogger("com.fr3ts0n.prot.kl");
|
||||
|
||||
commTimer = new Timer(commTimeoutTime, commTimeoutHandler);
|
||||
commTimer.setInitialDelay(commTimeoutTime);
|
||||
commTimer.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* construct with connecting to device
|
||||
*
|
||||
* @param device device to connect
|
||||
*/
|
||||
private KLHandlerGeneric(String device)
|
||||
{
|
||||
try
|
||||
{
|
||||
setDeviceName(device);
|
||||
} catch (Exception ex)
|
||||
{
|
||||
log.log(Level.SEVERE,"", ex);
|
||||
}
|
||||
commTimer = new Timer(commTimeoutTime, commTimeoutHandler);
|
||||
commTimer.setInitialDelay(commTimeoutTime);
|
||||
commTimer.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currBaudRate
|
||||
*/
|
||||
// current baud rate in use
|
||||
private int getCurrBaudRate()
|
||||
{
|
||||
return currBaudRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param currBaudRate the currBaudRate to set
|
||||
*/
|
||||
private void setCurrBaudRate(int currBaudRate)
|
||||
{
|
||||
firePropertyChange(new PropertyChangeEvent(this, "baud", this.currBaudRate, currBaudRate));
|
||||
this.currBaudRate = currBaudRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currAddress
|
||||
*/
|
||||
public int getCurrAddress()
|
||||
{
|
||||
return currAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param currAddress the currAddress to set
|
||||
*/
|
||||
public void setCurrAddress(int currAddress)
|
||||
{
|
||||
this.currAddress = currAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* close communication port
|
||||
*/
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
txTelegramQueue.clear();
|
||||
if (commTimer != null)
|
||||
{
|
||||
commTimer.stop();
|
||||
}
|
||||
super.close();
|
||||
// set shutdown status
|
||||
setProtStat(ProtStatus.OFFLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* add new listener for communication timeout
|
||||
*
|
||||
* @param listener new timeout listener
|
||||
*/
|
||||
public void addTimeoutListener(ActionListener listener)
|
||||
{
|
||||
commTimer.addActionListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* set port speed to specified baud rate
|
||||
*
|
||||
* @param newBaudRate new baud rate to be set
|
||||
*/
|
||||
private void setCustomBaudRate(int newBaudRate)
|
||||
{
|
||||
try
|
||||
{
|
||||
SerialExt.setCustomBaudrate(newBaudRate);
|
||||
} catch (Exception e)
|
||||
{
|
||||
log.log(Level.SEVERE,"Set custom baudrate", e);
|
||||
}
|
||||
|
||||
// show baudrate setting as debug output
|
||||
try
|
||||
{
|
||||
log.fine(String.format("Baudrate:%d/%d",
|
||||
SerialExt.getCustomBaudrate(),
|
||||
newBaudRate));
|
||||
} catch (Exception e)
|
||||
{
|
||||
log.log(Level.SEVERE,null, e);
|
||||
}
|
||||
// calculate new interByteTime (1M ns *numBits / bps)
|
||||
interByteTime = 1000000000 * numBitsPause / newBaudRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* send a single bit with 5 baud bit width
|
||||
*
|
||||
* @param bitValue
|
||||
*/
|
||||
private void sendBit5Baud(boolean bitValue)
|
||||
throws IOException
|
||||
{
|
||||
// set line status
|
||||
SerialExt.setBreak(bitValue ? 0 : 1);
|
||||
// RTS line follows inverse data bit ...
|
||||
// device.setRTS(!bitValue);
|
||||
// and wait a single bit time
|
||||
try
|
||||
{
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException e)
|
||||
{
|
||||
log.log(Level.SEVERE,null, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* send a byte with 5 baud line speed
|
||||
* this version sends out timed line break bits w/o changing the nominal
|
||||
* baud rate
|
||||
*
|
||||
* @param address CU to be addressed
|
||||
*/
|
||||
private void sendByte5Baud(int address)
|
||||
throws IOException
|
||||
{
|
||||
long start = System.currentTimeMillis();
|
||||
// ensure stop bit
|
||||
// sendBit5Baud(true);
|
||||
// start sending
|
||||
// device.setDTR(false);
|
||||
// start bit
|
||||
sendBit5Baud(false);
|
||||
// 8 data bits, LSB first
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
sendBit5Baud((address & (1 << i)) != 0);
|
||||
}
|
||||
// stop bit
|
||||
sendBit5Baud(true);
|
||||
// finish sending
|
||||
// device.setDTR(true);
|
||||
log.fine(String.format("TX-5Baud:%02X finished after %dms", address, System.currentTimeMillis() - start));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize communication by sending specified ECU address with 5 baud
|
||||
*
|
||||
* @param address ECU to be addressed
|
||||
* @return initialization status (0=OK, -1=Error)
|
||||
*/
|
||||
private void send5Baud(int address)
|
||||
throws IOException
|
||||
{
|
||||
int result = 0;
|
||||
setProtStat(ProtStatus.CONNECTING);
|
||||
|
||||
sendByte5Baud(address);
|
||||
message = "";
|
||||
// return status
|
||||
}
|
||||
|
||||
/**
|
||||
* send specified char to output device
|
||||
*
|
||||
* @param txByte byte to be sent
|
||||
* @param rememberTx remember last TX character
|
||||
*/
|
||||
private void writeChar(char txByte, boolean rememberTx)
|
||||
{
|
||||
try
|
||||
{
|
||||
log.fine("TX:" + String.format("%02X", (byte) txByte));
|
||||
|
||||
// if this byte should be remembered as TX byte, do it
|
||||
if (rememberTx)
|
||||
{
|
||||
lastTxChar = txByte;
|
||||
}
|
||||
SerialExt.sendChar((byte) txByte);
|
||||
pktStat = PacketStatus.ECHO;
|
||||
} catch (Exception ex)
|
||||
{
|
||||
log.log(Level.SEVERE,this.toString(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* confirm reception of last byte by sending complement of it back
|
||||
*
|
||||
* @param lastByte last received byte
|
||||
*/
|
||||
private void confirmByte(char lastByte)
|
||||
{
|
||||
// change to complement status ...
|
||||
pktStat = PacketStatus.COMPLEMENT;
|
||||
writeChar((char) ~lastByte, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for receiving chars from serial port
|
||||
*/
|
||||
class RxThread extends Thread
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
int chr;
|
||||
log.fine("Reader Thread started");
|
||||
while (getProtStat() != ProtStatus.OFFLINE && getProtStat() != ProtStatus.TIMEOUT)
|
||||
{
|
||||
try
|
||||
{
|
||||
chr = SerialExt.receiveChar();
|
||||
log.fine(String.format("RX:%02X : %c\t%s\t%s", chr, chr < 32 || chr > 127 ? '.' : chr,
|
||||
getProtStat(), pktStat));
|
||||
switch (getProtStat())
|
||||
{
|
||||
case RECEIVING:
|
||||
// restart comm timeout timer
|
||||
commTimer.restart();
|
||||
switch (pktStat)
|
||||
{
|
||||
case ECHO:
|
||||
lastTxChar = 0;
|
||||
// ignore the echo of sent complement
|
||||
pktStat = PacketStatus.DATA;
|
||||
break;
|
||||
|
||||
case COMPLEMENT:
|
||||
// ignore the echo of sent complement
|
||||
pktStat = PacketStatus.DATA;
|
||||
break;
|
||||
|
||||
case DATA:
|
||||
// remember time of last RX
|
||||
lastRxTime = System.currentTimeMillis();
|
||||
// add char to current RX message
|
||||
message += (char) chr;
|
||||
// do we have received a complete package?
|
||||
if (chr == 0x03 && message.length() > message.charAt(0))
|
||||
{
|
||||
//
|
||||
// package is complete
|
||||
//
|
||||
log.fine("RX:" + ProtUtils.hexDumpBuffer(message.toCharArray()));
|
||||
// update block counter with the received one
|
||||
blockCounter = message.charAt(1);
|
||||
// notify protocol handler of the new package
|
||||
messageHandler.handleTelegram(message.toCharArray());
|
||||
// clear the message
|
||||
message = "";
|
||||
// and change to send status
|
||||
setProtStat(ProtStatus.SENDING);
|
||||
sendNextByte();
|
||||
} else
|
||||
{
|
||||
//
|
||||
// package is still incomplete
|
||||
//
|
||||
|
||||
// and send out confirmation for received byte
|
||||
confirmByte((char) chr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SENDING:
|
||||
{
|
||||
switch (pktStat)
|
||||
{
|
||||
case ECHO:
|
||||
case DATA:
|
||||
// ignore the echo of sent data
|
||||
pktStat = PacketStatus.COMPLEMENT;
|
||||
break;
|
||||
|
||||
case COMPLEMENT:
|
||||
// restart comm timeout timer
|
||||
commTimer.restart();
|
||||
if (chr == (~lastTxChar & 0xFF))
|
||||
{
|
||||
pktStat = PacketStatus.DATA;
|
||||
sendNextByte();
|
||||
} else
|
||||
{
|
||||
log.log(Level.SEVERE,String.format("Wrong complement:%02X, expected:%02X", chr, ~lastTxChar));
|
||||
// TODO: handle communication error
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CONNECTING:
|
||||
{
|
||||
// if we receive the echo of the init byte, sending is done
|
||||
if (chr == lastTxChar)
|
||||
{
|
||||
// ignore echo byte
|
||||
} else
|
||||
{
|
||||
if (chr == SYNC_CHAR)
|
||||
{
|
||||
message = "";
|
||||
}
|
||||
// otherwise collect sync and key bytes
|
||||
message += (char) chr;
|
||||
// did we receive all INIT bytes (SYNC_CHAR, KW-lo, KW-hi)?
|
||||
if (message.length() > 2 && message.charAt(0) == SYNC_CHAR)
|
||||
{
|
||||
// notify protocol handler of initialization message to get keyword etc
|
||||
// messageHandler.handleTelegram(message.toCharArray());
|
||||
message = "";
|
||||
// Initialization is finished, change to status RECEIVING
|
||||
setProtStat(ProtStatus.RECEIVING);
|
||||
// confirm the last received byte
|
||||
confirmByte((char) chr);
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
log.log(Level.SEVERE,ex.toString());
|
||||
try
|
||||
{
|
||||
sleep(0);
|
||||
} catch (InterruptedException ex1)
|
||||
{
|
||||
log.log(Level.SEVERE,ex1.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
log.warning("Reader Tread finished");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write a telegram to serial port
|
||||
* implementation of SerialHandler
|
||||
*/
|
||||
@Override
|
||||
public int writeTelegram(char[] buffer)
|
||||
{
|
||||
return writeTelegram(buffer, 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* write a telegram to serial port
|
||||
* implementation of SerialHandler
|
||||
*/
|
||||
@Override
|
||||
public int writeTelegram(char[] buffer, int type, Object id)
|
||||
{
|
||||
return enqueueTelegram(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* start the serial handler
|
||||
* Implementation for compatibility
|
||||
*/
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
// start the receive thread
|
||||
new Thread()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
init5Baud(getCurrAddress());
|
||||
}
|
||||
}.start();
|
||||
try
|
||||
{
|
||||
Thread.sleep(500);
|
||||
} catch (Exception e)
|
||||
{
|
||||
log.log(Level.SEVERE,e.getMessage());
|
||||
}
|
||||
new RxThread().start();
|
||||
}
|
||||
|
||||
/**
|
||||
* send next available byte
|
||||
*
|
||||
* @return error status of dequeue and send operation
|
||||
*/
|
||||
private void sendNextByte()
|
||||
{
|
||||
int result = 0;
|
||||
// wait for slow ECUs
|
||||
try
|
||||
{
|
||||
// calculate remaining time to wait (Sytem time resolution sucks...)
|
||||
long tDiff = interByteTime - ((System.currentTimeMillis() - lastRxTime) * 1000000000);
|
||||
if (tDiff > 0)
|
||||
{
|
||||
log.fine("TX: waiting " + tDiff + " ns");
|
||||
Thread.sleep(tDiff / 1000000L, (int) (tDiff % 1000000L));
|
||||
}
|
||||
} catch (InterruptedException ex)
|
||||
{
|
||||
log.log(Level.SEVERE,"wait: " + ex.toString());
|
||||
}
|
||||
|
||||
// if we have to dequeue a new telegram ...
|
||||
if (currTxCharPos >= currTxTgm.length)
|
||||
{
|
||||
// ... then try to dequeue one
|
||||
result = dequeueTelegram();
|
||||
}
|
||||
// if there is something to send, send the next char
|
||||
if (result == 0)
|
||||
{
|
||||
writeChar(currTxTgm[currTxCharPos++], true);
|
||||
if (currTxCharPos >= currTxTgm.length)
|
||||
{
|
||||
setProtStat(ProtStatus.RECEIVING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* enqueue a telegram to be sent
|
||||
*
|
||||
* @param buffer telegram to be sent
|
||||
* @return error status of enqueue
|
||||
*/
|
||||
private int enqueueTelegram(char[] buffer)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
// if the queue is empty and current message is completely sent
|
||||
if (txTelegramQueue.size() == 0 && currTxCharPos >= currTxTgm.length)
|
||||
{
|
||||
// make buffer the current telegram
|
||||
currTxTgm = buffer;
|
||||
currTxCharPos = 0;
|
||||
} else
|
||||
{
|
||||
// otherwise put it into queue
|
||||
result = txTelegramQueue.add(buffer) ? 0 : -1;
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a acknowledge telegram for current protocol state
|
||||
*
|
||||
* @return ACK telegram with current block counter
|
||||
*/
|
||||
private char[] getAckTelegram()
|
||||
{
|
||||
return new char[]
|
||||
{
|
||||
0x03, ++blockCounter, 0x09, 0x03
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* dequeue next telegram to be sent
|
||||
*
|
||||
* @return error code of dequeue operation
|
||||
*/
|
||||
private int dequeueTelegram()
|
||||
{
|
||||
int result;
|
||||
// is there any telegram in the queue?
|
||||
if (txTelegramQueue.size() > 0)
|
||||
{
|
||||
// ... then dequeue it
|
||||
currTxTgm = txTelegramQueue.remove(0);
|
||||
// if necessary, adjust block counter
|
||||
if (currTxTgm[1] != (blockCounter + 1))
|
||||
{
|
||||
log.info(String.format("MsgCounter adjusted:%02x->%02x", (int) currTxTgm[1], (int) blockCounter + 1));
|
||||
currTxTgm[1] = ++blockCounter;
|
||||
}
|
||||
// ... and set byte pointer to start of telegram
|
||||
currTxCharPos = 0;
|
||||
result = 0;
|
||||
} else
|
||||
{
|
||||
// nothing in the pipe, so just send an acknowledge telegram
|
||||
currTxTgm = getAckTelegram();
|
||||
currTxCharPos = 0;
|
||||
result = 0;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize communication by sending specified ECU address with 5 baud
|
||||
*
|
||||
* @param address ECU to be addressed
|
||||
* @return baud rate of successful connection, or 0 if no connection could be established
|
||||
*/
|
||||
private synchronized void init5Baud(int address)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
// set current address
|
||||
setCurrAddress(address);
|
||||
try
|
||||
{
|
||||
// stop timeout handler
|
||||
commTimer.stop();
|
||||
// set device name / open port
|
||||
setDeviceName(deviceName);
|
||||
// loop through all known baud rates
|
||||
for (int i = 0; i < baudRates.length; i++)
|
||||
{
|
||||
setProtStat(ProtStatus.CONNECTING);
|
||||
log.info(String.format("Init Device:%s Address:%02x, Speed:%d", deviceName, address, baudRates[i]));
|
||||
// set communication baud rate
|
||||
setCustomBaudRate(baudRates[i]);
|
||||
// remember current baud rate
|
||||
setCurrBaudRate(baudRates[i]);
|
||||
// init communication with 5 baud address
|
||||
send5Baud(address);
|
||||
try
|
||||
{
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e)
|
||||
{
|
||||
log.log(Level.SEVERE,"Sleep", e);
|
||||
}
|
||||
// if we received an answer, we are not initializing any more
|
||||
if (getProtStat() != ProtStatus.CONNECTING)
|
||||
{
|
||||
log.info(String.format("Init OK Device:%s Address:%02x, Speed:%d", deviceName, address, baudRates[i]));
|
||||
// set return value
|
||||
result = getCurrBaudRate();
|
||||
// start communication timer
|
||||
commTimer.restart();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == 0)
|
||||
{
|
||||
log.warning(String.format("Init Timeout Device:%s Address:%02x", deviceName, address));
|
||||
close();
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
log.log(Level.SEVERE,deviceName + ": " + ex.toString());
|
||||
close();
|
||||
setProtStat(ProtStatus.ERROR);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
// remember current baud rate
|
||||
setCurrBaudRate(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The main routine for testing
|
||||
*
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String args[])
|
||||
{
|
||||
// set default parameters
|
||||
int address = 0x01;
|
||||
String device = "/dev/ttyUSB0";
|
||||
// update parameters by command line params
|
||||
if (args.length > 0)
|
||||
{
|
||||
device = args[0];
|
||||
}
|
||||
if (args.length > 1)
|
||||
{
|
||||
address = Integer.parseInt(args[1], 16);
|
||||
}
|
||||
|
||||
KLHandlerGeneric hdlr = new KLHandlerGeneric(device);
|
||||
|
||||
hdlr.init5Baud(address);
|
||||
|
||||
// wait until we are shutting down
|
||||
while (hdlr.getProtStat() != ProtStatus.CONNECTING
|
||||
&& hdlr.getProtStat() != ProtStatus.OFFLINE)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
hdlr.close();
|
||||
}
|
||||
}
|
||||
+455
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot.gui;
|
||||
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* Configuration GUI-Panel for RXTX Serial port object
|
||||
*
|
||||
* @author erwin
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class SerialConfigPanel
|
||||
extends javax.swing.JPanel
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = -8518189691304679418L;
|
||||
/** allow direct port changes from dialog changes? */
|
||||
private static final boolean doPortUpdates = true;
|
||||
/** ist the dialog initialized? */
|
||||
private boolean initialized = false;
|
||||
|
||||
/** Creates new form SerialConfigPanel */
|
||||
public SerialConfigPanel()
|
||||
{
|
||||
initComponents();
|
||||
initPortNames();
|
||||
}
|
||||
|
||||
/** Creates new form SerialConfigPanel */
|
||||
public SerialConfigPanel(SerialPort serPort)
|
||||
{
|
||||
initComponents();
|
||||
initPortNames();
|
||||
setPort(serPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize list of available port names for combo box
|
||||
*/
|
||||
private void initPortNames()
|
||||
{
|
||||
initialized = false;
|
||||
cbPort.addItem("");
|
||||
// initialize port selection
|
||||
CommPortIdentifier currPort;
|
||||
Enumeration ports = CommPortIdentifier.getPortIdentifiers();
|
||||
while (ports.hasMoreElements())
|
||||
{
|
||||
currPort = (CommPortIdentifier) ports.nextElement();
|
||||
if (currPort.getPortType() == CommPortIdentifier.PORT_SERIAL)
|
||||
{
|
||||
cbPort.addItem(currPort.getName());
|
||||
}
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all port parameters PORT -> DIALOG
|
||||
*/
|
||||
private void initPortParameters(SerialPort port)
|
||||
{
|
||||
initialized = false;
|
||||
if (port != null)
|
||||
{
|
||||
cbPort.setSelectedItem(port.getName());
|
||||
cbBaudrate.setSelectedItem(String.valueOf(port.getBaudRate()));
|
||||
cbParity.setSelectedIndex(port.getParity());
|
||||
cbDataBits.setSelectedIndex(port.getDataBits() - 5);
|
||||
cbStopBits.setSelectedIndex(port.getStopBits() - 1);
|
||||
// flow control combo's
|
||||
int prt = port.getFlowControlMode();
|
||||
cbProtocolRx.setSelectedIndex((prt & SerialPort.FLOWCONTROL_RTSCTS_IN) != 0 ? 1 : (prt & SerialPort.FLOWCONTROL_XONXOFF_IN) != 0 ? 2 : 0);
|
||||
cbProtocolTx.setSelectedIndex((prt & SerialPort.FLOWCONTROL_RTSCTS_OUT) != 0 ? 1 : (prt & SerialPort.FLOWCONTROL_XONXOFF_OUT) != 0 ? 2 : 0);
|
||||
btnDSR.setSelected(port.isDSR());
|
||||
btnCTS.setSelected(port.isCTS());
|
||||
btnCD.setSelected(port.isCD());
|
||||
btnDTR.setSelected(port.isDTR());
|
||||
btnRTS.setSelected(port.isRTS());
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all port parameters DIALOG -> PORT
|
||||
*/
|
||||
private void updatePortParameters(SerialPort port)
|
||||
{
|
||||
if (initialized && port != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
port.setSerialPortParams(Integer.valueOf(cbBaudrate.getSelectedItem().toString()).intValue(),
|
||||
cbDataBits.getSelectedIndex() + 5,
|
||||
cbStopBits.getSelectedIndex() + 1,
|
||||
cbParity.getSelectedIndex());
|
||||
// flow control parameters
|
||||
int mode = 0;
|
||||
mode |= (cbProtocolRx.getSelectedIndex() == 1) ? SerialPort.FLOWCONTROL_RTSCTS_IN : (cbProtocolRx.getSelectedIndex() == 2) ? SerialPort.FLOWCONTROL_XONXOFF_IN : 0;
|
||||
mode |= (cbProtocolTx.getSelectedIndex() == 1) ? SerialPort.FLOWCONTROL_RTSCTS_OUT : (cbProtocolTx.getSelectedIndex() == 2) ? SerialPort.FLOWCONTROL_XONXOFF_OUT : 0;
|
||||
port.setFlowControlMode(mode);
|
||||
} catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
*/
|
||||
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
|
||||
private void initComponents()
|
||||
{
|
||||
java.awt.GridBagConstraints gridBagConstraints;
|
||||
|
||||
javax.swing.JPanel panData = new javax.swing.JPanel();
|
||||
javax.swing.JLabel lblPort = new javax.swing.JLabel();
|
||||
cbPort = new javax.swing.JComboBox();
|
||||
javax.swing.JLabel lblBaudrate = new javax.swing.JLabel();
|
||||
cbBaudrate = new javax.swing.JComboBox();
|
||||
javax.swing.JLabel lblDataBits = new javax.swing.JLabel();
|
||||
cbDataBits = new javax.swing.JComboBox();
|
||||
javax.swing.JLabel lblStopBits = new javax.swing.JLabel();
|
||||
cbStopBits = new javax.swing.JComboBox();
|
||||
javax.swing.JLabel lblParity = new javax.swing.JLabel();
|
||||
cbParity = new javax.swing.JComboBox();
|
||||
javax.swing.JLabel lblHsRx = new javax.swing.JLabel();
|
||||
javax.swing.JLabel lblHsTx = new javax.swing.JLabel();
|
||||
cbProtocolRx = new javax.swing.JComboBox();
|
||||
cbProtocolTx = new javax.swing.JComboBox();
|
||||
javax.swing.JPanel jPanel1 = new javax.swing.JPanel();
|
||||
btnDSR = new javax.swing.JToggleButton();
|
||||
btnCTS = new javax.swing.JToggleButton();
|
||||
btnCD = new javax.swing.JToggleButton();
|
||||
btnDTR = new javax.swing.JToggleButton();
|
||||
btnRTS = new javax.swing.JToggleButton();
|
||||
|
||||
setLayout(new java.awt.BorderLayout());
|
||||
|
||||
panData.setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
lblPort.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
lblPort.setLabelFor(cbPort);
|
||||
lblPort.setText("Port");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5);
|
||||
panData.add(lblPort, gridBagConstraints);
|
||||
|
||||
cbPort.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
cbPort.addItemListener(new java.awt.event.ItemListener()
|
||||
{
|
||||
public void itemStateChanged(java.awt.event.ItemEvent evt)
|
||||
{
|
||||
cbPortItemStateChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
panData.add(cbPort, gridBagConstraints);
|
||||
|
||||
lblBaudrate.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
lblBaudrate.setLabelFor(cbBaudrate);
|
||||
lblBaudrate.setText("Baudrate");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5);
|
||||
panData.add(lblBaudrate, gridBagConstraints);
|
||||
|
||||
cbBaudrate.setEditable(true);
|
||||
cbBaudrate.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
cbBaudrate.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"300", "600", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"}));
|
||||
cbBaudrate.setSelectedIndex(5);
|
||||
cbBaudrate.addItemListener(new java.awt.event.ItemListener()
|
||||
{
|
||||
public void itemStateChanged(java.awt.event.ItemEvent evt)
|
||||
{
|
||||
SelectionChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
panData.add(cbBaudrate, gridBagConstraints);
|
||||
|
||||
lblDataBits.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
lblDataBits.setLabelFor(cbDataBits);
|
||||
lblDataBits.setText("Data Bits");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 3;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5);
|
||||
panData.add(lblDataBits, gridBagConstraints);
|
||||
|
||||
cbDataBits.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
cbDataBits.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"5", "6", "7", "8"}));
|
||||
cbDataBits.setSelectedIndex(3);
|
||||
cbDataBits.addItemListener(new java.awt.event.ItemListener()
|
||||
{
|
||||
public void itemStateChanged(java.awt.event.ItemEvent evt)
|
||||
{
|
||||
SelectionChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 3;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
panData.add(cbDataBits, gridBagConstraints);
|
||||
|
||||
lblStopBits.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
lblStopBits.setLabelFor(cbStopBits);
|
||||
lblStopBits.setText("Stop Bits");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 4;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5);
|
||||
panData.add(lblStopBits, gridBagConstraints);
|
||||
|
||||
cbStopBits.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
cbStopBits.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"1", "2", "1.5"}));
|
||||
cbStopBits.addItemListener(new java.awt.event.ItemListener()
|
||||
{
|
||||
public void itemStateChanged(java.awt.event.ItemEvent evt)
|
||||
{
|
||||
SelectionChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 4;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
panData.add(cbStopBits, gridBagConstraints);
|
||||
|
||||
lblParity.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
lblParity.setLabelFor(cbParity);
|
||||
lblParity.setText("Parity");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 2;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5);
|
||||
panData.add(lblParity, gridBagConstraints);
|
||||
|
||||
cbParity.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
cbParity.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"None", "Odd", "Even", "Mark", "Space"}));
|
||||
cbParity.addItemListener(new java.awt.event.ItemListener()
|
||||
{
|
||||
public void itemStateChanged(java.awt.event.ItemEvent evt)
|
||||
{
|
||||
SelectionChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 2;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
panData.add(cbParity, gridBagConstraints);
|
||||
|
||||
lblHsRx.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
lblHsRx.setText("Handshake Rx");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 5;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5);
|
||||
panData.add(lblHsRx, gridBagConstraints);
|
||||
|
||||
lblHsTx.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
lblHsTx.setText("Handshake Tx");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 6;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5);
|
||||
panData.add(lblHsTx, gridBagConstraints);
|
||||
|
||||
cbProtocolRx.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
cbProtocolRx.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"None", "RTS/CTS", "XON/XOFF"}));
|
||||
cbProtocolRx.addItemListener(new java.awt.event.ItemListener()
|
||||
{
|
||||
public void itemStateChanged(java.awt.event.ItemEvent evt)
|
||||
{
|
||||
SelectionChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 5;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
panData.add(cbProtocolRx, gridBagConstraints);
|
||||
|
||||
cbProtocolTx.setFont(new java.awt.Font("Dialog", 0, 10));
|
||||
cbProtocolTx.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"None", "RTS/CTS", "XON/XOFF"}));
|
||||
cbProtocolTx.addItemListener(new java.awt.event.ItemListener()
|
||||
{
|
||||
public void itemStateChanged(java.awt.event.ItemEvent evt)
|
||||
{
|
||||
SelectionChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 6;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
panData.add(cbProtocolTx, gridBagConstraints);
|
||||
|
||||
add(panData, java.awt.BorderLayout.CENTER);
|
||||
|
||||
jPanel1.setLayout(new java.awt.GridLayout(1, 0, 1, 0));
|
||||
|
||||
btnDSR.setFont(new java.awt.Font("Dialog", 0, 8));
|
||||
btnDSR.setText("DSR");
|
||||
btnDSR.setEnabled(false);
|
||||
btnDSR.setOpaque(false);
|
||||
jPanel1.add(btnDSR);
|
||||
|
||||
btnCTS.setFont(new java.awt.Font("Dialog", 0, 8));
|
||||
btnCTS.setText("CTS");
|
||||
btnCTS.setEnabled(false);
|
||||
btnCTS.setOpaque(false);
|
||||
jPanel1.add(btnCTS);
|
||||
|
||||
btnCD.setFont(new java.awt.Font("Dialog", 0, 8));
|
||||
btnCD.setText("CD");
|
||||
btnCD.setEnabled(false);
|
||||
btnCD.setOpaque(false);
|
||||
jPanel1.add(btnCD);
|
||||
|
||||
btnDTR.setFont(new java.awt.Font("Dialog", 0, 8));
|
||||
btnDTR.setText("DTR");
|
||||
btnDTR.setEnabled(false);
|
||||
btnDTR.setOpaque(false);
|
||||
jPanel1.add(btnDTR);
|
||||
|
||||
btnRTS.setFont(new java.awt.Font("Dialog", 0, 8));
|
||||
btnRTS.setText("RTS");
|
||||
btnRTS.setEnabled(false);
|
||||
btnRTS.setOpaque(false);
|
||||
jPanel1.add(btnRTS);
|
||||
|
||||
add(jPanel1, java.awt.BorderLayout.SOUTH);
|
||||
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void SelectionChanged(java.awt.event.ItemEvent evt)//GEN-FIRST:event_SelectionChanged
|
||||
{//GEN-HEADEREND:event_SelectionChanged
|
||||
if (doPortUpdates && evt.getStateChange() == ItemEvent.SELECTED)
|
||||
{
|
||||
updatePortParameters(port);
|
||||
}
|
||||
}//GEN-LAST:event_SelectionChanged
|
||||
|
||||
private void cbPortItemStateChanged(java.awt.event.ItemEvent evt)//GEN-FIRST:event_cbPortItemStateChanged
|
||||
{//GEN-HEADEREND:event_cbPortItemStateChanged
|
||||
// the port has been changed -> select thew new port
|
||||
if (initialized && evt.getStateChange() == ItemEvent.SELECTED)
|
||||
{
|
||||
String portName = String.valueOf(evt.getItem());
|
||||
SerialPort newPort;
|
||||
try
|
||||
{
|
||||
newPort = (SerialPort) CommPortIdentifier.getPortIdentifier(portName).open(portName, 1000);
|
||||
} catch (Exception e)
|
||||
{
|
||||
newPort = null;
|
||||
Logger.getLogger(getClass()).warn(e.getMessage());
|
||||
}
|
||||
|
||||
setPort(newPort);
|
||||
}
|
||||
}//GEN-LAST:event_cbPortItemStateChanged
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JToggleButton btnCD;
|
||||
private javax.swing.JToggleButton btnCTS;
|
||||
private javax.swing.JToggleButton btnDSR;
|
||||
private javax.swing.JToggleButton btnDTR;
|
||||
private javax.swing.JToggleButton btnRTS;
|
||||
private javax.swing.JComboBox cbBaudrate;
|
||||
private javax.swing.JComboBox cbDataBits;
|
||||
private javax.swing.JComboBox cbParity;
|
||||
private javax.swing.JComboBox cbPort;
|
||||
private javax.swing.JComboBox cbProtocolRx;
|
||||
private javax.swing.JComboBox cbProtocolTx;
|
||||
private javax.swing.JComboBox cbStopBits;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
/**
|
||||
* Holds value of property port.
|
||||
*/
|
||||
private SerialPort port;
|
||||
|
||||
/**
|
||||
* Getter for property device.
|
||||
*
|
||||
* @return Value of property device.
|
||||
*/
|
||||
public SerialPort getPort()
|
||||
{
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for serial Port.
|
||||
*
|
||||
* @param port New value of port.
|
||||
*/
|
||||
private void setPort(SerialPort port)
|
||||
{
|
||||
if (this.port != null)
|
||||
{
|
||||
this.port.removeEventListener();
|
||||
}
|
||||
this.port = port;
|
||||
initPortParameters(port);
|
||||
}
|
||||
}
|
||||
+379
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot.gui;
|
||||
|
||||
import com.fr3ts0n.prot.SerialExt;
|
||||
import com.fr3ts0n.prot.TelegramListener;
|
||||
import com.fr3ts0n.prot.TelegramWriter;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author erwin
|
||||
*/
|
||||
public class SerialHandler extends Thread
|
||||
implements TelegramWriter
|
||||
{
|
||||
/** the serial device */
|
||||
String deviceName = "/dev/ttyS0";
|
||||
/** current protocol status */
|
||||
private ProtStatus protStat = ProtStatus.UNKNOWN;
|
||||
/** file descriptor of serial device */
|
||||
private long serialDeviceDescriptor = -1;
|
||||
// the logger object
|
||||
static Logger log = Logger.getLogger("com.fr3ts0n.prot.ser");
|
||||
|
||||
/**
|
||||
* Status of protocol handler - to determine if we currently send / receive
|
||||
*/
|
||||
public enum ProtStatus
|
||||
{
|
||||
UNKNOWN,
|
||||
SETUP,
|
||||
INITIALIZED,
|
||||
CONNECTING,
|
||||
SENDING,
|
||||
RECEIVING,
|
||||
OFFLINE,
|
||||
TIMEOUT,
|
||||
ERROR,
|
||||
}
|
||||
|
||||
/** Colors for each protocol status */
|
||||
public static final Color[] statColor =
|
||||
{
|
||||
null,
|
||||
Color.YELLOW,
|
||||
null,
|
||||
Color.MAGENTA,
|
||||
Color.GREEN,
|
||||
Color.GREEN,
|
||||
null,
|
||||
null,
|
||||
Color.RED,
|
||||
};
|
||||
|
||||
/*
|
||||
FileInputStream rdr;
|
||||
FileOutputStream wrtr;
|
||||
*/
|
||||
RandomAccessFile rdr;
|
||||
RandomAccessFile wrtr;
|
||||
TelegramListener messageHandler;
|
||||
|
||||
// current receive message
|
||||
String message = "";
|
||||
|
||||
/**
|
||||
* Creates a new instance of SerialHandler
|
||||
*/
|
||||
public SerialHandler()
|
||||
{
|
||||
// setDeviceName(deviceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of SerialHandler
|
||||
*
|
||||
* @param device device name
|
||||
*/
|
||||
public SerialHandler(String device)
|
||||
{
|
||||
try
|
||||
{
|
||||
setDeviceName(device);
|
||||
} catch (IOException ex)
|
||||
{
|
||||
log.log(Level.SEVERE, "SerialHandler", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the protStat
|
||||
*/
|
||||
public ProtStatus getProtStat()
|
||||
{
|
||||
return protStat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param protStat the protStat to set
|
||||
*/
|
||||
void setProtStat(ProtStatus protStat)
|
||||
{
|
||||
firePropertyChange(new PropertyChangeEvent(this,
|
||||
"status",
|
||||
this.protStat,
|
||||
protStat));
|
||||
this.protStat = protStat;
|
||||
}
|
||||
|
||||
/**
|
||||
* return device/file name
|
||||
*
|
||||
* @return device name
|
||||
*/
|
||||
public String getDeviceName()
|
||||
{
|
||||
return (deviceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* close current connections
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (wrtr != null)
|
||||
{
|
||||
wrtr.close();
|
||||
wrtr = null;
|
||||
}
|
||||
if (rdr != null)
|
||||
{
|
||||
rdr.close();
|
||||
rdr = null;
|
||||
}
|
||||
} catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property deviceName.
|
||||
*
|
||||
* @param deviceName New value of property deviceName.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void setDeviceName(java.lang.String deviceName)
|
||||
throws IOException
|
||||
{
|
||||
// set up serial line ...
|
||||
close();
|
||||
// set new device name
|
||||
this.deviceName = deviceName;
|
||||
// get system file descriptor
|
||||
// serialDeviceDescriptor = SerialExt.setPortName(deviceName);
|
||||
// open java side file
|
||||
wrtr = new RandomAccessFile(deviceName, "rw");
|
||||
rdr = wrtr;
|
||||
// get system file descriptor
|
||||
serialDeviceDescriptor = getSystemFD();
|
||||
// and set it in serial extender
|
||||
SerialExt.serialPortDescriptor = (int) serialDeviceDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the numeric system file descriptor/handle
|
||||
*
|
||||
* @return numeric system file descriptor/handle
|
||||
*/
|
||||
private long getSystemFD()
|
||||
{
|
||||
long result = -1;
|
||||
Field dscrField;
|
||||
FileDescriptor dscr;
|
||||
try
|
||||
{
|
||||
// get java file descriptor
|
||||
dscr = wrtr.getFD();
|
||||
try
|
||||
{
|
||||
// try to get windows-specific field "handle"
|
||||
dscrField = FileDescriptor.class.getDeclaredField("handle");
|
||||
} catch (NoSuchFieldException ex)
|
||||
{
|
||||
// we are not windows... get field "fd"
|
||||
dscrField = FileDescriptor.class.getDeclaredField("fd");
|
||||
}
|
||||
// make field accessible
|
||||
dscrField.setAccessible(true);
|
||||
// and read it's value
|
||||
result = dscrField.getLong(dscr);
|
||||
} catch (Exception ex)
|
||||
{
|
||||
log.log(Level.SEVERE, "getFD", ex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* start the thread
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("fallthrough")
|
||||
public void run()
|
||||
{
|
||||
int chr;
|
||||
try
|
||||
{
|
||||
while ((chr = rdr.read()) >= 0)
|
||||
{
|
||||
switch (chr)
|
||||
{
|
||||
// ignore special characters
|
||||
case 13:
|
||||
case 32:
|
||||
break;
|
||||
|
||||
// trigger message handling for new request
|
||||
case '>':
|
||||
message += (char) chr;
|
||||
// trigger message handling
|
||||
case 10:
|
||||
if (messageHandler != null)
|
||||
messageHandler.handleTelegram(message.toCharArray());
|
||||
message = "";
|
||||
break;
|
||||
|
||||
default:
|
||||
message += (char) chr;
|
||||
}
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write a telegram to serial port
|
||||
*
|
||||
* @param buffer
|
||||
* @return result of write operation
|
||||
*/
|
||||
public int writeTelegram(char[] buffer)
|
||||
{
|
||||
return (writeTelegram(buffer, 0, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* write a telegram to serial port
|
||||
*
|
||||
* @param buffer message buffer to write
|
||||
* @param type message type
|
||||
* @param id message id
|
||||
* @return result of write operation
|
||||
*/
|
||||
public int writeTelegram(char[] buffer, int type, Object id)
|
||||
{
|
||||
int result = 0;
|
||||
try
|
||||
{
|
||||
String msg = new String(buffer);
|
||||
msg += "\n";
|
||||
wrtr.write(msg.getBytes());
|
||||
result = buffer.length;
|
||||
} catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/**
|
||||
* configure serial handler
|
||||
* this method informs about generic serial ports need to be
|
||||
* configured by the operating system (via startup script)
|
||||
*/
|
||||
public void configure()
|
||||
{
|
||||
log.info("Generic Serial ports have to be configured by the\n"
|
||||
+ "operating system (via startup script)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for property messageHandler.
|
||||
*
|
||||
* @return Value of property messageHandler.
|
||||
*/
|
||||
public TelegramListener getMessageHandler()
|
||||
{
|
||||
return messageHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property messageHandler.
|
||||
*
|
||||
* @param messageHandler New value of property messageHandler.
|
||||
*/
|
||||
public void setMessageHandler(TelegramListener messageHandler)
|
||||
{
|
||||
this.messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
/** Utility field used by event firing mechanism. */
|
||||
private Vector<PropertyChangeListener> listenerList = null;
|
||||
|
||||
/**
|
||||
* Registers PropertyChangeListener to receive events.
|
||||
*
|
||||
* @param listener The listener to register.
|
||||
*/
|
||||
public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
|
||||
{
|
||||
if (listenerList == null)
|
||||
{
|
||||
listenerList = new Vector<PropertyChangeListener>();
|
||||
}
|
||||
listenerList.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes PropertyChangeListener from the list of listeners.
|
||||
*
|
||||
* @param listener The listener to remove.
|
||||
*/
|
||||
public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
|
||||
{
|
||||
|
||||
listenerList.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all registered listeners about the event.
|
||||
*
|
||||
* @param event The event to be fired
|
||||
*/
|
||||
void firePropertyChange(PropertyChangeEvent event)
|
||||
{
|
||||
|
||||
if (listenerList == null) return;
|
||||
PropertyChangeListener listener;
|
||||
Iterator<PropertyChangeListener> it = listenerList.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
listener = it.next();
|
||||
listener.propertyChange(event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* (C) Copyright 2015 by fr3ts0n <erwin.scheuch-heilig@gmx.at>
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.fr3ts0n.prot.gui;
|
||||
|
||||
import com.fr3ts0n.prot.SerialExt;
|
||||
import com.fr3ts0n.prot.TelegramListener;
|
||||
import com.fr3ts0n.prot.TelegramWriter;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author erwin
|
||||
*/
|
||||
public class SerialHandlerGeneric extends Thread
|
||||
implements TelegramWriter
|
||||
{
|
||||
/** the serial device */
|
||||
String deviceName = "/dev/ttyS0";
|
||||
/** current protocol status */
|
||||
private ProtStatus protStat = ProtStatus.UNKNOWN;
|
||||
/** file descriptor of serial device */
|
||||
private long serialDeviceDescriptor = -1;
|
||||
// the logger object
|
||||
static Logger log = Logger.getLogger("com.fr3ts0n.prot.ser");
|
||||
|
||||
/**
|
||||
* Status of protocol handler - to determine if we currently send / receive
|
||||
*/
|
||||
public enum ProtStatus
|
||||
{
|
||||
UNKNOWN,
|
||||
SETUP,
|
||||
INITIALIZED,
|
||||
CONNECTING,
|
||||
SENDING,
|
||||
RECEIVING,
|
||||
OFFLINE,
|
||||
TIMEOUT,
|
||||
ERROR,
|
||||
}
|
||||
|
||||
/** Colors for each protocol status */
|
||||
public static final Color[] statColor =
|
||||
{
|
||||
null,
|
||||
Color.YELLOW,
|
||||
null,
|
||||
Color.MAGENTA,
|
||||
Color.GREEN,
|
||||
Color.GREEN,
|
||||
null,
|
||||
null,
|
||||
Color.RED,
|
||||
};
|
||||
|
||||
/*
|
||||
FileInputStream rdr;
|
||||
FileOutputStream wrtr;
|
||||
*/
|
||||
private RandomAccessFile rdr;
|
||||
private RandomAccessFile wrtr;
|
||||
TelegramListener messageHandler;
|
||||
|
||||
// current receive message
|
||||
String message = "";
|
||||
|
||||
/**
|
||||
* Creates a new instance of SerialHandler
|
||||
*/
|
||||
SerialHandlerGeneric()
|
||||
{
|
||||
// setDeviceName(deviceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of SerialHandler
|
||||
*
|
||||
* @param device device name
|
||||
*/
|
||||
public SerialHandlerGeneric(String device)
|
||||
{
|
||||
try
|
||||
{
|
||||
setDeviceName(device);
|
||||
} catch (IOException ex)
|
||||
{
|
||||
log.log(Level.SEVERE,"SerialHandlerGeneric", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the protStat
|
||||
*/
|
||||
ProtStatus getProtStat()
|
||||
{
|
||||
return protStat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param protStat the protStat to set
|
||||
*/
|
||||
void setProtStat(ProtStatus protStat)
|
||||
{
|
||||
firePropertyChange(new PropertyChangeEvent(this,
|
||||
"status",
|
||||
this.protStat,
|
||||
protStat));
|
||||
this.protStat = protStat;
|
||||
}
|
||||
|
||||
/**
|
||||
* return device/file name
|
||||
*
|
||||
* @return device name
|
||||
*/
|
||||
public String getDeviceName()
|
||||
{
|
||||
return (deviceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* close current connections
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (wrtr != null)
|
||||
{
|
||||
wrtr.close();
|
||||
wrtr = null;
|
||||
}
|
||||
if (rdr != null)
|
||||
{
|
||||
rdr.close();
|
||||
rdr = null;
|
||||
}
|
||||
} catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property deviceName.
|
||||
*
|
||||
* @param deviceName New value of property deviceName.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void setDeviceName(java.lang.String deviceName)
|
||||
throws IOException
|
||||
{
|
||||
// set up serial line ...
|
||||
close();
|
||||
// set new device name
|
||||
this.deviceName = deviceName;
|
||||
// get system file descriptor
|
||||
// serialDeviceDescriptor = SerialExt.setPortName(deviceName);
|
||||
// open java side file
|
||||
wrtr = new RandomAccessFile(deviceName, "rw");
|
||||
rdr = wrtr;
|
||||
// get system file descriptor
|
||||
serialDeviceDescriptor = getSystemFD();
|
||||
// and set it in serial extender
|
||||
SerialExt.serialPortDescriptor = (int) serialDeviceDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the numeric system file descriptor/handle
|
||||
*
|
||||
* @return numeric system file descriptor/handle
|
||||
*/
|
||||
private long getSystemFD()
|
||||
{
|
||||
long result = -1;
|
||||
Field dscrField;
|
||||
FileDescriptor dscr;
|
||||
try
|
||||
{
|
||||
// get java file descriptor
|
||||
dscr = wrtr.getFD();
|
||||
try
|
||||
{
|
||||
// try to get windows-specific field "handle"
|
||||
dscrField = FileDescriptor.class.getDeclaredField("handle");
|
||||
} catch (NoSuchFieldException ex)
|
||||
{
|
||||
// we are not windows... get field "fd"
|
||||
dscrField = FileDescriptor.class.getDeclaredField("fd");
|
||||
}
|
||||
// make field accessible
|
||||
dscrField.setAccessible(true);
|
||||
// and read it's value
|
||||
result = dscrField.getLong(dscr);
|
||||
} catch (Exception ex)
|
||||
{
|
||||
log.log(Level.SEVERE,"getFD", ex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* start the thread
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("fallthrough")
|
||||
public void run()
|
||||
{
|
||||
int chr;
|
||||
try
|
||||
{
|
||||
while ((chr = rdr.read()) >= 0)
|
||||
{
|
||||
switch (chr)
|
||||
{
|
||||
// ignore special characters
|
||||
case 13:
|
||||
case 32:
|
||||
break;
|
||||
|
||||
// trigger message handling for new request
|
||||
case '>':
|
||||
message += (char) chr;
|
||||
// trigger message handling
|
||||
case 10:
|
||||
if (messageHandler != null)
|
||||
messageHandler.handleTelegram(message.toCharArray());
|
||||
message = "";
|
||||
break;
|
||||
|
||||
default:
|
||||
message += (char) chr;
|
||||
}
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write a telegram to serial port
|
||||
*
|
||||
* @param buffer
|
||||
* @return result of write operation
|
||||
*/
|
||||
public int writeTelegram(char[] buffer)
|
||||
{
|
||||
return (writeTelegram(buffer, 0, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* write a telegram to serial port
|
||||
*
|
||||
* @param buffer message buffer to write
|
||||
* @param type message type
|
||||
* @param id message id
|
||||
* @return result of write operation
|
||||
*/
|
||||
public int writeTelegram(char[] buffer, int type, Object id)
|
||||
{
|
||||
int result = 0;
|
||||
try
|
||||
{
|
||||
String msg = new String(buffer);
|
||||
msg += "\n";
|
||||
wrtr.write(msg.getBytes());
|
||||
result = buffer.length;
|
||||
} catch (IOException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/**
|
||||
* configure serial handler
|
||||
* this method informs about generic serial ports need to be
|
||||
* configured by the operating system (via startup script)
|
||||
*/
|
||||
public void configure()
|
||||
{
|
||||
log.info("Generic Serial ports have to be configured by the\n"
|
||||
+ "operating system (via startup script)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for property messageHandler.
|
||||
*
|
||||
* @return Value of property messageHandler.
|
||||
*/
|
||||
public TelegramListener getMessageHandler()
|
||||
{
|
||||
return messageHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property messageHandler.
|
||||
*
|
||||
* @param messageHandler New value of property messageHandler.
|
||||
*/
|
||||
public void setMessageHandler(TelegramListener messageHandler)
|
||||
{
|
||||
this.messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
/** Utility field used by event firing mechanism. */
|
||||
private Vector<PropertyChangeListener> listenerList = null;
|
||||
|
||||
/**
|
||||
* Registers PropertyChangeListener to receive events.
|
||||
*
|
||||
* @param listener The listener to register.
|
||||
*/
|
||||
public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
|
||||
{
|
||||
if (listenerList == null)
|
||||
{
|
||||
listenerList = new Vector<PropertyChangeListener>();
|
||||
}
|
||||
listenerList.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes PropertyChangeListener from the list of listeners.
|
||||
*
|
||||
* @param listener The listener to remove.
|
||||
*/
|
||||
public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
|
||||
{
|
||||
|
||||
listenerList.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all registered listeners about the event.
|
||||
*
|
||||
* @param event The event to be fired
|
||||
*/
|
||||
void firePropertyChange(PropertyChangeEvent event)
|
||||
{
|
||||
|
||||
if (listenerList == null) return;
|
||||
PropertyChangeListener listener;
|
||||
Iterator<PropertyChangeListener> it = listenerList.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
listener = it.next();
|
||||
listener.propertyChange(event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* protocol stuff with GUI dependecies
|
||||
*/
|
||||
/**
|
||||
* @author erwin
|
||||
*
|
||||
*/
|
||||
package com.fr3ts0n.prot.gui;
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<body>
|
||||
Communication protocol stacks and communication-related helper classes
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user