/*
* (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.ecu.prot.vag;
import com.fr3ts0n.ecu.EcuCodeItem;
import com.fr3ts0n.ecu.EcuCodeList;
import com.fr3ts0n.ecu.EcuDataItem;
import com.fr3ts0n.ecu.EcuDataItems;
import com.fr3ts0n.ecu.EcuDataPv;
import com.fr3ts0n.ecu.VagConversion;
import com.fr3ts0n.prot.ProtUtils;
import com.fr3ts0n.prot.ProtoHeader;
import com.fr3ts0n.prot.TelegramListener;
import com.fr3ts0n.prot.TelegramWriter;
import com.fr3ts0n.prot.gui.KLHandler;
import com.fr3ts0n.pvs.PvList;
import org.apache.log4j.Logger;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Vector;
/**
* Keyword 1281 protocol (VAG diagnostic protocol)
*
* @author erwin
*/
public class Kw1281Prot extends ProtoHeader
implements TelegramListener,
TelegramWriter
{
// command for clearing fault codes
static final char CMD_CLEAR_DFCs = 0x05;
// command for END communication
static final char CMD_END_COMM = 0x06;
// command for reading fault codes
static final char CMD_READ_DFCs = 0x07;
// command for reading single data
static final char CMD_READ_SINGLE = 0x08;
// Acknowledge command
static final char CMD_ACK = 0x09;
// ID for responded NO DATA available
static final char ID_NODATA = 0x0A;
// command for group reading of data items
static final char CMD_GROUP_READ = 0x29;
// ID for responded ASCII data
static final char ID_ASCII_DATA = 0xF6;
// ID for responded ASCII data
static final char ID_DFC_DATA = 0xFC;
// ID for responded GROUP READING data
static final char ID_GRPREAD_DATA = 0xE7;
// ID for responded header for GROUP READING DATA
static final char ID_GRPINFO_HEAD = 0x02;
// ID for responded GROUP READING DATA
static final char ID_GRPINFO_DATA = 0xF4;
// block end marker
static final char BLOCK_END = 0x03;
/** service ID for idle opeation */
public static final int SVC_NONE = 0;
/** service ID for reading fault codes */
public static final int SVC_READ_DFCS = 1;
/** service ID for clearing fault codes */
public static final int SVC_CLEAR_DFCS = 2;
/** service ID for reading single data group */
public static final int SVC_READ_DATA_GRP = 3;
/** service ID for reading all data */
public static final int SVC_READ_DATA_ALL = 4;
/** service ID for shutting down communication */
public static final int SVC_SHUTDOWN = 5;
/** service ID for shutting down communication */
public static final int SVC_FINISHED = 6;
/** currently selected service */
private int service = SVC_NONE;
/** Number of codes set */
private int numCodes = 0;
// static telegram footer definition
static final char[] tgmFooter =
{
BLOCK_END
};
// static telegram empty payload
static final char[] tgmEmpty =
{
};
// Telegram field id's
static final int FLD_ID_LEN = 0;
static final int FLD_ID_BLKCNT = 1;
static final int FLD_ID_CMD = 2;
// number of data items in BLKREAD data block
static final int BLK_NUM_ITEMS = 4;
/**
* List of telegram parameters in order of appearance
*/
static final int TGM_PARAMETERS[][] =
/* START, LEN, PARAM-TYPE // REMARKS */
/* ------------------------------------------- */
{
{
0, 1, PT_NUMERIC
}, // ID_LEN
{
1, 1, PT_NUMERIC
}, // ID_BLKCNT
{
2, 1, PT_NUMERIC
}, // ID_CMD
};
/**
* Descriptors of telegram parameters
*/
static final String FLD_DESCRIPTORS[] =
{
"Length ",
"BlockCnt",
"Command ",
};
// data items to be used for data display
EcuDataItems itms = new EcuDataItems("prot/vag/res/vag_pids.csv", "prot/vag/res/vag_conversions.csv");
/** List of ECU data items */
public static PvList PidPvs = new PvList();
/** ECU vehicle identification items */
public static PvList VidPvs = new PvList();
/** current fault codes */
public static PvList tCodes = new PvList();
/** list of known fault codes */
public static EcuCodeList knownCodes = new EcuCodeList("com.fr3ts0n.ecu.prot.vag.res.codes");
/** running telegram block counter */
char blockCounter = 0;
/** current data group which was requested */
private char currDataGroup = 0;
/** selected data group to be requested next time */
private char selectedDataGroup = 1;
/** Vector of all Items within current group data frame */
private Vector<EcuDataItem> currGrpItems;
/** Map of all known Group data items */
public HashMap<Integer, Vector<EcuDataItem>> knownGrpItems =
new HashMap<Integer, Vector<EcuDataItem>>();
/** name of last preset saved/loaded */
protected String lastPresetName = null;
/**
* Default constructor
*/
public Kw1281Prot()
{
super();
log = Logger.getLogger("com.fr3ts0n.prot.1281");
initialize();
}
/**
* Initialize protocol
*/
public void initialize()
{
// init
VidPvs.clear();
PidPvs.clear();
// init TC list with "NO codes set"
tCodes.clear();
tCodes.put(Integer.valueOf(0), knownCodes.get(Integer.valueOf(0)));
setNumCodes(0);
// initialize map of known data items
knownGrpItems.clear();
for (int i = 0; i <= 0xFF; i++)
{
knownGrpItems.put(Integer.valueOf(i), new Vector<EcuDataItem>());
}
currDataGroup = selectedDataGroup = 0;
currGrpItems = knownGrpItems.get(Integer.valueOf(currDataGroup));
// notify about property change
firePropertyChange(new PropertyChangeEvent(this, "preset", null, knownGrpItems));
}
/**
* load preset data
*/
protected void loadPreset()
{
Thread loadThd = new Thread()
{
@Override
public void run()
{
EcuDataPv vid = (EcuDataPv) VidPvs.get(0);
String fileName = vid.get(EcuDataPv.FID_VALUE).toString().trim() + ".prs";
if (fileName.equals(lastPresetName))
{
log.info("Preset already loaded:" + fileName);
} else
{
log.info("Load Preset: " + fileName);
try
{
BufferedReader rdr = new BufferedReader(new FileReader(fileName));
knownGrpItems.clear();
PidPvs.clear();
while (rdr.ready())
{
String line = rdr.readLine();
// forget about empty, or remarked lines
if (line.trim().length() == 0
|| line.startsWith("#")
|| line.startsWith("//")) continue;
String params[] = line.split("\t");
Integer frmNum = Integer.valueOf(params[0], 0x10);
// List of all Items within group
Vector<EcuDataItem> grpVec = new Vector<EcuDataItem>();
// loop through all items for this group
for (int i = 1; i < params.length && params[i].length() > 0; i++)
{
Vector<EcuDataItem> currVec = itms.getPidDataItems(ID_GRPINFO_DATA,
Integer.parseInt(params[i], 0x10));
// add all items in list to corresponding group vector
Iterator<EcuDataItem> it = currVec.iterator();
while (it.hasNext())
{
EcuDataItem itm = (EcuDataItem) it.next().clone();
itm.pid = frmNum;
itm.ofs = i - 1;
itm.pv.put(EcuDataPv.FID_PID, Integer.valueOf(itm.pid));
itm.pv.put(EcuDataPv.FID_OFS, Integer.valueOf(itm.ofs));
grpVec.add(itm);
}
}
// make items known items
knownGrpItems.put(frmNum, grpVec);
}
log.info("Preset loaded: " + fileName);
// notify about property change
firePropertyChange(new PropertyChangeEvent(this, "preset", lastPresetName, fileName));
// remember name of preset
lastPresetName = fileName;
rdr.close();
} catch (IOException ex)
{
log.warn("LoadPreset: " + ex.toString());
}
}
}
};
// MIN priority to NOT disturb communication
loadThd.setPriority(Thread.MIN_PRIORITY);
loadThd.start();
}
/**
* save current preset data
*/
protected void savePreset()
{
Thread saveThd = new Thread()
{
@Override
public void run()
{
EcuDataPv vid = (EcuDataPv) VidPvs.get(0);
String fileName = vid.get(EcuDataPv.FID_VALUE).toString().trim() + ".prs";
// notify about property change
firePropertyChange(new PropertyChangeEvent(this, "preset", lastPresetName, fileName));
// remember preset
lastPresetName = fileName;
// 1st VID is used as preset filename
File pstFile = new File(fileName);
// if file aleady exists, we don't save it
if (!pstFile.exists())
{
log.info("Save Preset: " + fileName);
FileWriter wtr = null;
try
{
wtr = new FileWriter(pstFile);
// Loop through all known data grous
Iterator<Entry<Integer, Vector<EcuDataItem>>> it = knownGrpItems.entrySet().iterator();
while (it.hasNext())
{
Entry<Integer, Vector<EcuDataItem>> itmSet = it.next();
// write group number
wtr.write(String.format("%02X\t", itmSet.getKey()));
// loop through all items within data group
Vector<EcuDataItem> itms = itmSet.getValue();
Iterator<EcuDataItem> itItm = itms.iterator();
while (itItm.hasNext())
{
EcuDataItem currItm = itItm.next();
// write PID of item
wtr.write(String.format("%02X\t", currItm.pid));
}
// finish data group entry
wtr.write("\n");
}
log.info("Preset saved: " + fileName);
} catch (IOException ex)
{
log.error("SavePreset: " + ex.toString());
} finally
{
try
{
wtr.close();
} catch (IOException ex)
{
log.error("SavePreset: " + ex.toString());
}
}
} else
{
log.info("Preset saving skipped: " + fileName);
}
}
};
// MIN priority to NOT disturb communication
saveThd.setPriority(Thread.MIN_PRIORITY);
saveThd.start();
}
/* (non-Javadoc)
* @see com.fr3ts0n.prot.ProtoHeader#getFooter(char[])
*/
@Override
public char[] getFooter(char[] buffer)
{
return tgmFooter;
}
/* (non-Javadoc)
* @see com.fr3ts0n.prot.ProtoHeader#getNewHeader(char[])
*/
@Override
protected char[] getNewHeader(char[] buffer)
{
return getNewHeader(buffer, CMD_ACK, null);
}
/* (non-Javadoc)
* @see com.fr3ts0n.prot.ProtoHeader#getNewHeader(char[], int, java.lang.Object)
*/
@Override
protected char[] getNewHeader(char[] buffer, int type, Object id)
{
char[] hdr = createEmptyHeader();
// set parameters
setParamInt(FLD_ID_LEN, hdr, buffer.length + 3);
setParamInt(FLD_ID_BLKCNT, hdr, ++blockCounter);
setParamInt(FLD_ID_CMD, hdr, type);
return (hdr);
}
/* (non-Javadoc)
* @see com.fr3ts0n.prot.ProtoHeader#getParamDescriptors()
*/
@Override
protected String[] getParamDescriptors()
{
return FLD_DESCRIPTORS;
}
/* (non-Javadoc)
* @see com.fr3ts0n.prot.ProtoHeader#getTelegramParams()
*/
@Override
public int[][] getTelegramParams()
{
return TGM_PARAMETERS;
}
/**
* check telegram if it meets protocol requirements
* current implementation only performs a size check, any other check
* needs to be implemented in sub-class
*
* @param buffer = current telegram buffer
* @return true if telegram is OK, otherwise false
*/
@Override
public boolean checkTelegram(char[] buffer)
{
return (buffer.length >= java.lang.Math.max(getHeaderLength() + getFooterLength(), getParamInt(FLD_ID_LEN, buffer)));
}
/**
* get next supported data group
*
* @return next supported data group
*/
char getNextDataGroup()
{
char grp = getCurrDataGroup();
// search next item only makes sense if there is at least one more ...
if (knownGrpItems.size() > 0)
{
// search next valid data group
while (knownGrpItems.get(Integer.valueOf(++grp)) == null)
{/* just search */}
}
if (grp == 0) grp++;
// return new group number
return (grp);
}
/**
* send request to read group data
*
* @param groupNum data group to be read
* @return result of writeTelegram @see writeTelegram
*/
int requestGroupData(char groupNum)
{
setCurrDataGroup(groupNum);
// set list of group data items
currGrpItems = knownGrpItems.get(Integer.valueOf(getCurrDataGroup()));
char[] payLoad =
{
groupNum
};
return (writeTelegram(payLoad, CMD_GROUP_READ, null));
}
/**
* send request to read DFCs
*
* @return result of writeTelegram @see writeTelegram
*/
int requestDFCs()
{
return (writeTelegram(tgmEmpty, CMD_READ_DFCs, null));
}
/**
* send request to clear DFCs
*
* @return result of writeTelegram @see writeTelegram
*/
int requestClearDFCs()
{
return (writeTelegram(tgmEmpty, CMD_CLEAR_DFCs, null));
}
/**
* send ACK telegram
*
* @return result of writeTelegram @see writeTelegram
*/
int requestACK()
{
return (writeTelegram(tgmEmpty, CMD_ACK, null));
}
/**
* send request to end communication
*
* @return result of writeTelegram @see writeTelegram
*/
int requestEndComm()
{
return (writeTelegram(tgmEmpty, CMD_END_COMM, null));
}
/**
* @return the service
*/
public /** currently selected service */
int getService()
{
return service;
}
/**
* @param service the service to set
*/
public void setService(int service)
{
if (service != this.service)
{
this.service = service;
// immediate dialog actions ...
switch (service)
{
case SVC_CLEAR_DFCS:
case SVC_READ_DFCS:
tCodes.clear();
setNumCodes(0);
break;
case SVC_READ_DATA_ALL:
showAllGroupItems();
break;
case SVC_READ_DATA_GRP:
break;
}
}
}
/**
* Getter for property numCodes.
*
* @return Value of property numCodes.
*/
public int getNumCodes()
{
return this.numCodes;
}
/**
* Setter for property numCodes.
*
* @param numCodes New value of property numCodes.
*/
public void setNumCodes(int numCodes)
{
firePropertyChange(new PropertyChangeEvent(this, "numCodes", this.numCodes, numCodes));
this.numCodes = numCodes;
}
/**
* @return the selectedDataGroup
*/
public /** selected data group to be requested next time */
char getSelectedDataGroup()
{
return selectedDataGroup;
}
/**
* @param selectedDataGroup the selectedDataGroup to set
*/
public void setSelectedDataGroup(char selectedDataGroup)
{
this.selectedDataGroup = selectedDataGroup;
}
/**
* @return the currDataGroup
*/
public /** current data group which was requested */
char getCurrDataGroup()
{
return currDataGroup;
}
/**
* Show all known group items
*/
void showAllGroupItems()
{
Iterator<Integer> itKeys = knownGrpItems.keySet().iterator();
while (itKeys.hasNext())
{
showGroupItems(itKeys.next());
}
}
/**
* show all data items of selected group
* * if there are other items shown, it does not hide them.
*
* @param groupNum
*/
void showGroupItems(int groupNum)
{
// get items of goup
Vector<EcuDataItem> grpItms = knownGrpItems.get(groupNum);
if (grpItms != null)
{
// loop through items in group
Iterator<EcuDataItem> itItm = grpItms.iterator();
while (itItm.hasNext())
{
EcuDataItem itm = itItm.next();
PidPvs.put(itm.pv.toString(), itm.pv);
}
}
}
/**
* @param currDataGroup the currDataGroup to set
*/
private void setCurrDataGroup(char currDataGroup)
{
// if data group changes in single group mode ...
if (service == SVC_READ_DATA_GRP
&& currDataGroup != this.currDataGroup)
{
// ... clear PID-PVs to create new data list at reception
PidPvs.clear();
showGroupItems(currDataGroup);
}
this.currDataGroup = currDataGroup;
}
/**
* handle incoming protocol telegram
* default implementaion only checks telegram and notifies listeners with
* protocol payload
*
* @param buffer - telegram buffer
* @return number of listeners notified
*/
@Override
public int handleTelegram(char[] buffer)
{
int cnt = 0;
log.debug("RX:" + ProtUtils.hexDumpBuffer(buffer));
// if telegram is OK
if (checkTelegram(buffer))
{
// get command
int cmd = getParamInt(FLD_ID_CMD, buffer);
// update block counter
blockCounter = (char) getParamInt(FLD_ID_BLKCNT, buffer).intValue();
// get payload
char[] payLoad = getPayLoad(buffer);
switch (cmd)
{
case ID_GRPINFO_HEAD:
// field number within group
int fldId = 0;
// clear list of current group data items
// currGrpItems.clear();
// loop through all data items within telegram
for (int i = 0; i < payLoad.length; )
{
// get data id from group reading
int dId = (int) payLoad[i];
// get the corresponding data items for svc/pid
Vector<EcuDataItem> pidItems = itms.getPidDataItems(ID_GRPINFO_DATA, dId);
// if item was found ...
if (pidItems != null && pidItems.size() > 0)
{
EcuDataItem currItm;
// if item already exists
if (currGrpItems.size() > fldId)
{
// re-use existing item
currItm = currGrpItems.get(fldId);
} else
{
// otherwise clone a new one
currItm = (EcuDataItem) pidItems.get(0).clone();
// set specific values for this item
currItm.pid = (int) getCurrDataGroup();
currItm.ofs += fldId;
currItm.pv.put(EcuDataPv.FID_PID, Integer.valueOf(currItm.pid));
currItm.pv.put(EcuDataPv.FID_OFS, Integer.valueOf(currItm.ofs));
// ensure there are enough elements in list
while (currGrpItems.size() <= fldId)
currGrpItems.add(null);
// add item to list of group data items
currGrpItems.set(fldId, currItm);
}
// update metadata
int numTblChrs = payLoad[i + 2];
// if conversion is a VagConversion, we may adjust meta parameters
if (currItm.cnv[0] instanceof VagConversion)
{
// set meta parameter for conversion
((VagConversion) currItm.cnv[0]).setMetaNw(payLoad[i + 1]);
// any following table data available?
if (numTblChrs != 0)
{
// set table values for conversion
((VagConversion) currItm.cnv[0]).setMetaTblValues(String.valueOf(payLoad, i + 3, numTblChrs).toCharArray());
}
}
// increment byte index to next entry
i += 3 + numTblChrs;
// increment field number
fldId++;
}
}
showGroupItems(getCurrDataGroup());
// now request again to get real data
requestGroupData(getCurrDataGroup());
break;
case ID_GRPINFO_DATA:
if (currGrpItems == null || currGrpItems.size() < BLK_NUM_ITEMS)
{
log.error(String.format("Missing/Incomplete Metadata for GRP:%d", (int) getCurrDataGroup()));
}
{
for (int i = 0; i < Math.min(payLoad.length, currGrpItems.size()); i++)
{
EcuDataItem currItm = currGrpItems.get(i);
if (currItm != null)
{
// and update corresponding process var
currItm.updatePvFomBuffer(payLoad);
} else
{
log.error(String.format("Data w/o meta GRP:%d, ITM:%d", (int) getCurrDataGroup(), i));
}
}
}
// if we do group reading and desired group has not changed ...
if (service == SVC_READ_DATA_GRP && getCurrDataGroup() == getSelectedDataGroup())
{
// request same group again
requestGroupData(getCurrDataGroup());
} else
{
// otherwise close this group by requesting ACK
requestACK();
}
break;
case ID_GRPREAD_DATA:
// currGrpItems.clear();
// loop through all 4 entries of group
for (int i = 0; i < payLoad.length; i += 3)
{
// get data it from group reading
int dId = (int) payLoad[i];
// get the corresponding data items for svc/pid
Vector<EcuDataItem> pidItems = itms.getPidDataItems(cmd, dId);
// if item was found ...
if (pidItems != null)
{
// loop through all data items for this dId
Iterator<EcuDataItem> it = pidItems.iterator();
while (it.hasNext())
{
EcuDataItem currItm = (EcuDataItem) it.next().clone();
// set specific values for this item
currItm.pid = (int) getCurrDataGroup();
currItm.ofs += i / 3;
currItm.pv.put(EcuDataPv.FID_PID, Integer.valueOf(currItm.pid));
currItm.pv.put(EcuDataPv.FID_OFS, Integer.valueOf(currItm.ofs));
// ensure there are enough elements in list
while (currGrpItems.size() < (i / 3))
currGrpItems.add(null);
// add item to list of group data items
currGrpItems.set(i / 3, currItm);
// and update corresponding process var
currItm.updatePvFomBuffer(Arrays.copyOfRange(payLoad, i + 1, i + 3));
}
} else
{
log.warn("Unknown data ID:" + dId);
}
}
// if we do group reading and desired group has not changed ...
if (service == SVC_READ_DATA_GRP && getCurrDataGroup() == getSelectedDataGroup())
{
// request same group again
requestGroupData(getCurrDataGroup());
} else
{
// otherwise close this group by requesting ACK
requestACK();
}
break;
case CMD_ACK:
switch (service)
{
case SVC_READ_DATA_ALL:
// request next available data group
requestGroupData(getNextDataGroup());
break;
case SVC_READ_DATA_GRP:
// ensure new selection of group is updated
setCurrDataGroup(getSelectedDataGroup());
// request same group again
requestGroupData(getCurrDataGroup());
break;
case SVC_READ_DFCS:
// clear fault code list
tCodes.clear();
setNumCodes(0);
// request failure codes
requestDFCs();
break;
case SVC_CLEAR_DFCS:
// Request clearing DFCs ...
requestClearDFCs();
// ... and continue with Reading DFCc
setService(SVC_READ_DFCS);
break;
case SVC_SHUTDOWN:
requestEndComm();
// now set to Service NONE
setService(SVC_FINISHED);
break;
case SVC_NONE:
default:
requestACK();
break;
}
break;
case ID_NODATA:
log.info(String.format("NODATA: Group:%d -> remove", (int) getCurrDataGroup()));
// since data is not available, remove group from map ...
knownGrpItems.remove(Integer.valueOf(getCurrDataGroup()));
// if we finished the initial turaround, save preset data
if (currDataGroup == 0)
{
savePreset();
}
// request ACK
requestACK();
break;
case ID_DFC_DATA:
int nCodes = numCodes;
// loop through all codes reported
for (int i = 0; i < payLoad.length; i += 3)
{
// get code number and status
int dfcNum = getParamInt(i, 2, payLoad);
int dfcStat = getParamInt(i + 2, 1, payLoad);
// enter code into code list for visualisation
EcuCodeItem code = knownCodes.get(dfcNum);
// if code is not known ...
if (code == null)
{
// create new one and add it to list of known codes
code = new EcuCodeItem(dfcNum, "Unknown Fault code");
}
code.put(EcuCodeItem.FID_STATUS, Integer.valueOf(dfcStat));
tCodes.put(dfcNum, code);
if (dfcNum != 0xFFFF)
{
nCodes++;
// set the MIL status based on code status
nCodes |= dfcStat & 0x80;
}
}
// set number of codes
setNumCodes(nCodes);
// finish service since we received corresponding answer
setService(SVC_NONE);
// further DFCs may still come after ACK ...
requestACK();
break;
case ID_ASCII_DATA:
// save vehicle ID data
EcuDataPv pv = new EcuDataPv();
pv.put(EcuDataPv.FID_DESCRIPT, "ID");
pv.put(EcuDataPv.FID_VALUE, String.valueOf(payLoad));
VidPvs.put(VidPvs.size(), pv);
// if this is the first VID dataset, try to load corresponding preset
if (VidPvs.size() == 1) loadPreset();
// send ACK
requestACK();
break;
default:
requestACK();
break;
}
cnt++;
}
return (cnt);
}
/**
* Protocol simulation thread
* This may be started to use the program in demonstration mode w/o any
* adaptor/vehicle connected
*/
public Thread simulation = new Thread()
{
@Override
@SuppressWarnings("fallthrough")
public void run()
{
char i = 0;
// handle ID_ASCII_DATA
handleTelegram(createTelegram("1234567890".toCharArray(), Kw1281Prot.ID_ASCII_DATA, null));
// handle ID_ASCII_DATA
handleTelegram(createTelegram("SIMULATION".toCharArray(), Kw1281Prot.ID_ASCII_DATA, null));
// handle ID_ASCII_DATA
handleTelegram(createTelegram("TEST".toCharArray(), Kw1281Prot.ID_ASCII_DATA, null));
setCurrDataGroup((char) 1);
setSelectedDataGroup((char) 1);
handleTelegram(createTelegram("".toCharArray(), CMD_ACK, null));
while (true)
{
switch (service)
{
case SVC_CLEAR_DFCS:
case SVC_READ_DFCS:
// handleTelegram(createTelegram(new char[]{0x02,0x0D,0x9A,0x02,0x0E,0x1B}, ID_DFC_DATA, null));
handleTelegram(createTelegram(new char[]{0x46, 0x3A, 0xA3, 0x02, 0x01, 0x9B, 0x02, 0x0D, 0x9A}, ID_DFC_DATA, null));
break;
case SVC_READ_DATA_ALL:
case SVC_READ_DATA_GRP:
if (service == SVC_READ_DATA_ALL || getSelectedDataGroup() != getCurrDataGroup())
{
handleTelegram(createTelegram("".toCharArray(), CMD_ACK, null));
// handle ID_GRPINFO_HEAD
handleTelegram(createTelegram(new char[]
{
0x80, 0x20, 0x00,
0x8C, 0x30, 0x11, 0x00, 0x0C, 0x18, 0x24, 0x30, 0x3C, 0x48, 0x54, 0x60, 0x6C, 0x78, 0x84, 0x90, 0x9C, 0xA8, 0xAC, 0xB8,
0x85, 0x05, 0x00,
0x88, 0xFF, 0x00
}, ID_GRPINFO_HEAD, null));
}
handleTelegram(createTelegram(new char[]{i, i, i, i++}, ID_GRPINFO_DATA, null));
break;
}
try
{
Thread.sleep(50);
} catch (Exception e)
{/* do nothing */}
}
}
};
/**
* main routine for testing modules
*
* @param args
*/
public static void main(String[] args)
{
final Kw1281Prot prt = new Kw1281Prot();
if (args.length > 0)
{
// set default parameters
final int adress = args.length > 1 ? Integer.parseInt(args[1], 16) : 0x01;
final String device = args.length > 0 ? args[0] : "/dev/ttyUSB0";
final KLHandler adapt = new KLHandler(device);
// connect telegram layers
prt.addTelegramWriter(adapt);
adapt.setMessageHandler(prt);
/** Handler for communication Timeout */
adapt.addTimeoutListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
log.warn("CommTimeout -> re-initializing");
adapt.init5Baud(adress);
}
});
prt.setService(SVC_READ_DATA_ALL);
// initialize communication
if (adapt.init5Baud(adress) != 0)
{
// wait until we are shutting down
while (adapt.getProtStat() != KLHandler.ProtStatus.OFFLINE)
{
try
{
Thread.sleep(500);
} catch (Exception e)
{
log.error(null, e);
}
}
}
adapt.close();
} else
{
// otherwise run simulation
prt.setService(SVC_READ_DATA_ALL);
prt.simulation.run();
}
}
}