android: AndrOBD library vendored (no submodule, no git link)

This commit is contained in:
“Naeel”
2026-05-25 09:36:38 +04:00
parent 361fe8803d
commit b3b044572c
193 changed files with 61446 additions and 8 deletions
@@ -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
View File
@@ -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 -&gt; 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 -&gt; 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
View File
@@ -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;