mirror of https://github.com/rusefi/RomRaider.git
Add new NCS logging protocol support
This commit is contained in:
parent
e51606d7f7
commit
150d10df19
|
@ -0,0 +1,3 @@
|
|||
# use a : to separate possible table names to match against
|
||||
ltft_table_column_names=Learning map TP shaft lattice point table:
|
||||
ltft_table_row_names=Learning map N shaft lattice point table:
|
Binary file not shown.
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.io.j2534.api;
|
||||
|
||||
import static com.romraider.io.protocol.ncs.iso14230.NCSChecksumCalculator.calculateChecksum;
|
||||
import static com.romraider.util.HexUtil.asHex;
|
||||
import static com.romraider.util.ParamChecker.checkNotNull;
|
||||
import static java.lang.System.arraycopy;
|
||||
import static org.apache.log4j.Logger.getLogger;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.romraider.io.connection.ConnectionManager;
|
||||
import com.romraider.io.connection.ConnectionProperties;
|
||||
import com.romraider.io.connection.KwpConnectionProperties;
|
||||
import com.romraider.io.j2534.api.J2534Impl.Config;
|
||||
import com.romraider.io.j2534.api.J2534Impl.Flag;
|
||||
import com.romraider.io.j2534.api.J2534Impl.Protocol;
|
||||
import com.romraider.io.j2534.api.J2534Impl.TxFlags;
|
||||
import com.romraider.logger.ecu.comms.manager.PollingState;
|
||||
|
||||
public final class J2534ConnectionISO14230 implements ConnectionManager {
|
||||
private static final Logger LOGGER = getLogger(J2534ConnectionISO14230.class);
|
||||
private J2534 api = null;
|
||||
private int LOOPBACK = 0;
|
||||
private int channelId;
|
||||
private int deviceId;
|
||||
private int msgId;
|
||||
private byte[] lastResponse;
|
||||
private long timeout;
|
||||
private boolean commsStarted;
|
||||
private final byte[] startReq = {
|
||||
(byte) 0x81, (byte) 0x10, (byte) 0xFC, (byte) 0x81, (byte) 0x0E};
|
||||
private final byte[] stopReq = {
|
||||
(byte) 0x81, (byte) 0x10, (byte) 0xFC, (byte) 0x82, (byte) 0x0F};
|
||||
|
||||
public J2534ConnectionISO14230(ConnectionProperties connectionProperties, String library) {
|
||||
checkNotNull(connectionProperties, "connectionProperties");
|
||||
deviceId = -1;
|
||||
commsStarted = false;
|
||||
timeout = (long)connectionProperties.getConnectTimeout();
|
||||
initJ2534(connectionProperties, library);
|
||||
LOGGER.info("J2534/ISO14230 connection initialised");
|
||||
}
|
||||
|
||||
// Send request and wait for response with known length
|
||||
public void send(byte[] request, byte[] response, PollingState pollState) {
|
||||
checkNotNull(request, "request");
|
||||
checkNotNull(response, "response");
|
||||
checkNotNull(pollState, "pollState");
|
||||
|
||||
if (pollState.getCurrentState() == PollingState.State.STATE_0 &&
|
||||
pollState.getLastState() == PollingState.State.STATE_1) {
|
||||
clearLine();
|
||||
}
|
||||
|
||||
if (pollState.getCurrentState() == PollingState.State.STATE_0) {
|
||||
api.writeMsg(channelId, request, timeout, TxFlags.NO_FLAGS);
|
||||
}
|
||||
api.readMsg(channelId, response, timeout);
|
||||
|
||||
if (pollState.getCurrentState() == PollingState.State.STATE_1){
|
||||
if ( (response[0] + 2) == response.length
|
||||
&& response[response.length - 1] == calculateChecksum(response)) {
|
||||
|
||||
lastResponse = new byte[response.length];
|
||||
arraycopy(response, 0, lastResponse, 0, response.length);
|
||||
}
|
||||
else{
|
||||
LOGGER.error(String.format(
|
||||
"J2534/ISO14230 Bad Data response: %s", asHex(response)));
|
||||
arraycopy(lastResponse, 0, response, 0, response.length);
|
||||
pollState.setNewQuery(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send request and wait specified time for response with unknown length
|
||||
public byte[] send(byte[] request) {
|
||||
checkNotNull(request, "request");
|
||||
api.writeMsg(channelId, request, timeout, TxFlags.NO_FLAGS);
|
||||
return api.readMsg(channelId, 1, timeout);
|
||||
}
|
||||
|
||||
public void clearLine() {
|
||||
boolean repeat = true;
|
||||
while (repeat) {
|
||||
LOGGER.debug("J2534/ISO14230 sending line break");
|
||||
int p3_min = getP3Min();
|
||||
setP3Min(2);
|
||||
api.writeMsg(
|
||||
channelId,
|
||||
stopReq,
|
||||
0L,
|
||||
TxFlags.WAIT_P3_MIN_ONLY);
|
||||
setP3Min(p3_min);
|
||||
api.clearBuffers(channelId);
|
||||
boolean empty = false;
|
||||
int i = 1;
|
||||
do {
|
||||
byte[] badBytes = api.readMsg(channelId, 700L);
|
||||
if (badBytes.length > 0) {
|
||||
LOGGER.debug(String.format(
|
||||
"J2534/ISO14230 clearing line (stale data %d): %s", i, asHex(badBytes)));
|
||||
empty = false;
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
empty = true;
|
||||
repeat = false;
|
||||
}
|
||||
} while (!empty && i <= 3);
|
||||
}
|
||||
try {
|
||||
fastInit();
|
||||
}
|
||||
catch (J2534Exception e) {
|
||||
// If fastInit fails because the ECU is no longer responding, for
|
||||
// a variety of reasons, ignore it and close off the connection
|
||||
// cleanly
|
||||
LOGGER.error(String.format(
|
||||
"J2534/ISO14230 Error performing fast initialization after clearing line: %s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
if (commsStarted) stopComms();
|
||||
commsStarted = false;
|
||||
}
|
||||
catch (J2534Exception e) {
|
||||
// If the stop command fails because the ECU is no longer responding, for
|
||||
// a variety of reasons, ignore it and close off the connection
|
||||
// cleanly
|
||||
LOGGER.error(String.format(
|
||||
"J2534/ISO14230 Error stopping communications after clearing line: %s", e.getMessage()));
|
||||
}
|
||||
stopMsgFilter();
|
||||
disconnectChannel();
|
||||
closeDevice();
|
||||
}
|
||||
|
||||
private void initJ2534(ConnectionProperties connectionProperties, String library) {
|
||||
try {
|
||||
api = new J2534Impl(Protocol.ISO14230, library);
|
||||
deviceId = api.open();
|
||||
try {
|
||||
version(deviceId);
|
||||
channelId = api.connect(
|
||||
deviceId, Flag.ISO9141_NO_CHECKSUM.getValue(),
|
||||
connectionProperties.getBaudRate());
|
||||
setConfig(channelId, (KwpConnectionProperties) connectionProperties);
|
||||
msgId = api.startPassMsgFilter(channelId, (byte) 0x00, (byte) 0x00);
|
||||
LOGGER.debug(String.format(
|
||||
"J2534/ISO14230 connection success: deviceId:%d, channelId:%d, msgId:%d, baud:%d",
|
||||
deviceId, channelId, msgId, connectionProperties.getBaudRate()));
|
||||
fastInit();
|
||||
commsStarted = true;
|
||||
} catch (Exception e) {
|
||||
LOGGER.debug(String.format(
|
||||
"J2534/ISO14230 exception: deviceId:%d, channelId:%d, msgId:%d",
|
||||
deviceId, channelId, msgId));
|
||||
close();
|
||||
throw new J2534Exception(String.format(
|
||||
"J2534/ISO14230 Error opening device: %s",e.getMessage()), e);
|
||||
}
|
||||
} catch (J2534Exception e) {
|
||||
if (deviceId != -1) api.close(deviceId);
|
||||
api = null;
|
||||
throw new J2534Exception(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void version(int deviceId) {
|
||||
if (!LOGGER.isDebugEnabled()) return;
|
||||
final Version version = api.readVersion(deviceId);
|
||||
LOGGER.info(String.format(
|
||||
"J2534 Version => firmware: %s, dll: %s, api: %s",
|
||||
version.firmware, version.dll, version.api));
|
||||
}
|
||||
|
||||
private void setConfig(int channelId, KwpConnectionProperties connectionProperties) {
|
||||
final ConfigItem p1Max = new ConfigItem(Config.P1_MAX.getValue(),
|
||||
(connectionProperties.getP1Max() * 2));
|
||||
final ConfigItem p3Min = new ConfigItem(Config.P3_MIN.getValue(),
|
||||
(connectionProperties.getP3Min() * 2));
|
||||
final ConfigItem p4Min = new ConfigItem(Config.P4_MIN.getValue(),
|
||||
(connectionProperties.getP4Min() * 2));
|
||||
final ConfigItem loopback = new ConfigItem(Config.LOOPBACK.getValue(),
|
||||
LOOPBACK);
|
||||
final ConfigItem dataBits = new ConfigItem(
|
||||
Config.DATA_BITS.getValue(),
|
||||
(connectionProperties.getDataBits() == 8 ? 0 : 1));
|
||||
final ConfigItem parity = new ConfigItem(
|
||||
Config.PARITY.getValue(),
|
||||
connectionProperties.getParity());
|
||||
api.setConfig(channelId, dataBits, parity, p1Max, p3Min, p4Min, loopback);
|
||||
LOGGER.debug(String.format("J2534/ISO14230 connection properties: %s",
|
||||
connectionProperties.toString()));
|
||||
}
|
||||
|
||||
private void stopMsgFilter() {
|
||||
try {
|
||||
api.stopMsgFilter(channelId, msgId);
|
||||
LOGGER.debug(String.format(
|
||||
"J2534/ISO14230 stopped message filter:%s", msgId));
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn(String.format(
|
||||
"J2534/ISO14230 Error stopping msg filter: %s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void disconnectChannel() {
|
||||
try {
|
||||
api.disconnect(channelId);
|
||||
LOGGER.debug(String.format(
|
||||
"J2534/ISO14230 disconnected channel:%d", channelId));
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn(String.format(
|
||||
"J2534/ISO14230 Error disconnecting channel: %s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void closeDevice() {
|
||||
try {
|
||||
api.close(deviceId);
|
||||
LOGGER.info(String.format(
|
||||
"J2534/ISO14230 closed connection to device:%d", deviceId));
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn(String.format(
|
||||
"J2534/ISO14230 Error closing device: %s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void fastInit() {
|
||||
final byte[] timing = api.fastInit(channelId, startReq);
|
||||
LOGGER.debug(String.format(
|
||||
"J2534/ISO14230 Fast Init: deviceId:%d, channelId:%d, timing:%s",
|
||||
deviceId, channelId, asHex(timing)));
|
||||
}
|
||||
|
||||
private void stopComms() {
|
||||
final byte[] response = send(stopReq);
|
||||
LOGGER.debug(String.format("Stop comms Response = %s", asHex(response)));
|
||||
}
|
||||
|
||||
private void setP3Min(int msec) {
|
||||
final ConfigItem p3_min = new ConfigItem(
|
||||
Config.P3_MIN.getValue(),
|
||||
msec);
|
||||
api.setConfig(channelId, p3_min);
|
||||
LOGGER.trace(String.format("Config set P3_MIN value = %d msec", msec / 2));
|
||||
}
|
||||
|
||||
private int getP3Min() {
|
||||
final ConfigItem[] configs = api.getConfig(
|
||||
channelId,
|
||||
Config.P3_MIN.getValue());
|
||||
int i = 10;
|
||||
for (ConfigItem item : configs) {
|
||||
if (Config.get(item.parameter) == Config.P3_MIN) {
|
||||
i = item.value;
|
||||
}
|
||||
}
|
||||
LOGGER.trace(String.format("Config get P3_MIN value = %d msec", i / 2));
|
||||
return i;
|
||||
}
|
||||
//
|
||||
// private void addressLoadReset() {
|
||||
// final byte[] loadReset = {
|
||||
// (byte) 0x02,
|
||||
// (byte) 0xAC, (byte) 0x81
|
||||
// (byte) 0x04, (byte) 0x21, (byte) 0x00, (byte) 0x04, (byte) 0x01, (byte) 0x2A
|
||||
// };
|
||||
// //04210004012A
|
||||
// api.writeMsg(channelId, loadReset, 155L, TxFlags.NO_FLAGS);
|
||||
// LOGGER.debug(String.format("loadReset Request = %s", asHex(loadReset)));
|
||||
// final byte[] response = api.readMsg(channelId, 1, 2000L);
|
||||
// LOGGER.debug(String.format("loadReset Response = %s", asHex(response)));
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.io.protocol;
|
||||
|
||||
import com.romraider.logger.ecu.comms.manager.PollingState;
|
||||
import com.romraider.logger.ecu.definition.Module;
|
||||
|
||||
|
||||
public interface ProtocolNCS extends Protocol {
|
||||
|
||||
byte[] constructEcuFastInitRequest(Module module);
|
||||
|
||||
byte[] constructReadSidPidRequest(Module module, byte sid, byte[][] pid);
|
||||
|
||||
byte[] constructLoadAddressRequest(byte[][] addresses);
|
||||
|
||||
void validateLoadAddressResponse(byte[] response);
|
||||
|
||||
void checkValidSidPidResponse(byte[] response);
|
||||
|
||||
byte[] constructReadAddressRequest(Module module, byte[][] bs,
|
||||
PollingState pollState);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.io.protocol.ncs.iso14230;
|
||||
|
||||
import static com.romraider.util.ByteUtil.asByte;
|
||||
import static com.romraider.util.ByteUtil.asInt;
|
||||
|
||||
public final class NCSChecksumCalculator {
|
||||
|
||||
private NCSChecksumCalculator() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static byte calculateChecksum(byte[] bytes) {
|
||||
int total = 0;
|
||||
for (int i = 0; i < (bytes.length - 1); i++) {
|
||||
byte b = bytes[i];
|
||||
total += asInt(b);
|
||||
}
|
||||
return asByte(total - ((total >>> 8) << 8));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.io.protocol.ncs.iso14230;
|
||||
|
||||
import static com.romraider.io.protocol.ncs.iso14230.NCSResponseProcessor.extractResponseData;
|
||||
import static com.romraider.io.protocol.ncs.iso14230.NCSResponseProcessor.filterRequestFromResponse;
|
||||
import static com.romraider.util.ParamChecker.checkNotNull;
|
||||
import static com.romraider.util.ParamChecker.checkNotNullOrEmpty;
|
||||
import static java.lang.System.arraycopy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.romraider.io.protocol.Protocol;
|
||||
import com.romraider.io.protocol.ProtocolNCS;
|
||||
import com.romraider.logger.ecu.comms.io.protocol.LoggerProtocolNCS;
|
||||
import com.romraider.logger.ecu.comms.manager.PollingState;
|
||||
import com.romraider.logger.ecu.comms.query.EcuInit;
|
||||
import com.romraider.logger.ecu.comms.query.EcuInitCallback;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQuery;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQueryData;
|
||||
import com.romraider.logger.ecu.definition.Module;
|
||||
|
||||
public final class NCSLoggerProtocol implements LoggerProtocolNCS {
|
||||
private final ProtocolNCS protocol = new NCSProtocol();
|
||||
|
||||
@Override
|
||||
public byte[] constructEcuFastInitRequest(Module module) {
|
||||
return protocol.constructEcuFastInitRequest(module);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructEcuInitRequest(Module module) {
|
||||
return protocol.constructEcuInitRequest(module);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructEcuResetRequest(Module module, int resetCode) {
|
||||
return protocol.constructEcuResetRequest(module, resetCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadAddressRequest(Module module,
|
||||
Collection<EcuQuery> queries) {
|
||||
return protocol.constructReadAddressRequest(
|
||||
module, new byte[0][0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadAddressRequest(
|
||||
Module module, Collection<EcuQuery> queries, PollingState pollState) {
|
||||
return protocol.constructReadAddressRequest(
|
||||
module, new byte[0][0], pollState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadSidPidRequest(Module module, byte sid, byte[] pid) {
|
||||
final byte[][] request = new byte[1][pid.length];
|
||||
arraycopy(pid, 0, request[0], 0, pid.length);
|
||||
return protocol.constructReadSidPidRequest(module, sid, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructLoadAddressRequest(Collection<EcuQuery> queries) {
|
||||
Collection<EcuQuery> filteredQueries = filterDuplicates(queries);
|
||||
return protocol.constructLoadAddressRequest(
|
||||
convertToByteAddresses(filteredQueries));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateLoadAddressResponse(byte[] response) {
|
||||
protocol.validateLoadAddressResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadAddressResponse(
|
||||
Collection<EcuQuery> queries, PollingState pollState) {
|
||||
|
||||
checkNotNullOrEmpty(queries, "queries");
|
||||
// length
|
||||
// one byte - Response sid
|
||||
// one byte - option
|
||||
// variable bytes of data defined for pid
|
||||
// checksum
|
||||
Collection<EcuQuery> filteredQueries = filterDuplicates(queries);
|
||||
int numAddresses = 0;
|
||||
for (EcuQuery ecuQuery : filteredQueries) {
|
||||
numAddresses += EcuQueryData.getDataLength(ecuQuery);
|
||||
}
|
||||
return new byte[(numAddresses + 4)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] preprocessResponse(
|
||||
byte[] request, byte[] response, PollingState pollState) {
|
||||
|
||||
return filterRequestFromResponse(request, response, pollState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processEcuInitResponse(EcuInitCallback callback, byte[] response) {
|
||||
checkNotNull(callback, "callback");
|
||||
checkNotNullOrEmpty(response, "response");
|
||||
EcuInit ecuInit = protocol.parseEcuInitResponse(response);
|
||||
callback.callback(ecuInit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processReadSidPidResponse(byte[] response) {
|
||||
checkNotNullOrEmpty(response, "response");
|
||||
protocol.checkValidSidPidResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processEcuResetResponse(byte[] response) {
|
||||
checkNotNullOrEmpty(response, "response");
|
||||
protocol.checkValidEcuResetResponse(response);
|
||||
}
|
||||
|
||||
// processes the response bytes and sets individual responses on corresponding query objects
|
||||
@Override
|
||||
public void processReadAddressResponses(
|
||||
Collection<EcuQuery> queries, byte[] response, PollingState pollState) {
|
||||
|
||||
checkNotNullOrEmpty(queries, "queries");
|
||||
checkNotNullOrEmpty(response, "response");
|
||||
final byte[] responseData = extractResponseData(response);
|
||||
final Collection<EcuQuery> filteredQueries = filterDuplicates(queries);
|
||||
final Map<String, byte[]> addressResults = new HashMap<String, byte[]>();
|
||||
int i = 0;
|
||||
for (EcuQuery filteredQuery : filteredQueries) {
|
||||
final int dataLength = EcuQueryData.getDataLength(filteredQuery);
|
||||
final byte[] data = new byte[dataLength];
|
||||
arraycopy(responseData, i, data, 0, dataLength);
|
||||
addressResults.put(filteredQuery.getHex(), data);
|
||||
i += dataLength;
|
||||
}
|
||||
for (EcuQuery query : queries) {
|
||||
query.setResponse(addressResults.get(query.getHex()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Protocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructWriteAddressRequest(
|
||||
Module module, byte[] writeAddress, byte value) {
|
||||
|
||||
return protocol.constructWriteAddressRequest(module, writeAddress, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processWriteResponse(byte[] data, byte[] response) {
|
||||
checkNotNullOrEmpty(data, "data");
|
||||
checkNotNullOrEmpty(response, "response");
|
||||
protocol.checkValidWriteResponse(data, response);
|
||||
}
|
||||
|
||||
private Collection<EcuQuery> filterDuplicates(Collection<EcuQuery> queries) {
|
||||
Collection<EcuQuery> filteredQueries = new ArrayList<EcuQuery>();
|
||||
for (EcuQuery query : queries) {
|
||||
if (!filteredQueries.contains(query)) {
|
||||
filteredQueries.add(query);
|
||||
}
|
||||
}
|
||||
return filteredQueries;
|
||||
}
|
||||
|
||||
private byte[][] convertToByteAddresses(Collection<EcuQuery> queries) {
|
||||
int byteCount = 0;
|
||||
for (EcuQuery query : queries) {
|
||||
byteCount += query.getAddresses().length;
|
||||
}
|
||||
byte[][] addresses = new byte[byteCount][];
|
||||
int i = 0;
|
||||
for (EcuQuery query : queries) {
|
||||
byte[] bytes = query.getBytes();
|
||||
int addrCount = query.getAddresses().length;
|
||||
int addrLen = bytes.length / addrCount;
|
||||
for (int j = 0; j < addrCount; j++) {
|
||||
final byte[] addr = new byte[addrLen];
|
||||
arraycopy(bytes, j * addrLen, addr, 0, addr.length);
|
||||
addresses[i++] = addr;
|
||||
}
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,405 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.io.protocol.ncs.iso14230;
|
||||
|
||||
import static com.romraider.io.protocol.ncs.iso14230.NCSChecksumCalculator.calculateChecksum;
|
||||
import static com.romraider.util.HexUtil.asHex;
|
||||
import static com.romraider.util.ParamChecker.checkNotNull;
|
||||
import static com.romraider.util.ParamChecker.checkNotNullOrEmpty;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.romraider.io.connection.ConnectionProperties;
|
||||
import com.romraider.io.connection.KwpConnectionProperties;
|
||||
import com.romraider.io.protocol.ProtocolNCS;
|
||||
import com.romraider.logger.ecu.comms.manager.PollingState;
|
||||
import com.romraider.logger.ecu.comms.query.EcuInit;
|
||||
import com.romraider.logger.ecu.comms.query.NCSEcuInit;
|
||||
import com.romraider.logger.ecu.definition.Module;
|
||||
import com.romraider.logger.ecu.exception.InvalidResponseException;
|
||||
import com.romraider.logger.ecu.exception.UnsupportedProtocolException;
|
||||
|
||||
public final class NCSProtocol implements ProtocolNCS {
|
||||
private final ByteArrayOutputStream bb = new ByteArrayOutputStream(255);
|
||||
public static final byte PHY_ADDR = (byte) 0x80;
|
||||
public static final byte READ_MEMORY_PADDING = (byte) 0x00;
|
||||
public static final byte READ_MEMORY_COMMAND = (byte) 0xA0;
|
||||
public static final byte READ_MEMORY_RESPONSE = (byte) 0xE0;
|
||||
public static final byte LOAD_ADDRESS_COMMAND = (byte) 0xAC;
|
||||
public static final byte LOAD_ADDRESS_RESPONSE = (byte) 0xEC;
|
||||
public static final byte READ_LOAD_COMMAND = (byte) 0x21;
|
||||
public static final byte READ_LOAD_RESPONSE = (byte) 0x61;
|
||||
public static final byte WRITE_MEMORY_COMMAND = (byte) 0xB0;
|
||||
public static final byte WRITE_MEMORY_RESPONSE = (byte) 0xF0;
|
||||
public static final byte WRITE_ADDRESS_COMMAND = (byte) 0xB8;
|
||||
public static final byte WRITE_ADDRESS_RESPONSE = (byte) 0xF8;
|
||||
public static final byte FASTINIT_COMMAND = (byte) 0x81;
|
||||
public static final byte FASTINIT_RESPONSE = (byte) 0xC1;
|
||||
public static final byte ECU_ID_SID = (byte) 0x1A;
|
||||
public static final byte OPTION_81 = (byte) 0x81;
|
||||
public static final byte FIELD_TYPE_01 = (byte) 0x01;
|
||||
public static final byte FIELD_TYPE_02 = (byte) 0x02;
|
||||
public static final byte FIELD_TYPE_83 = (byte) 0x83;
|
||||
public static final byte SID_21 = (byte) 0x21;
|
||||
public static final byte SID_22 = (byte) 0x22;
|
||||
public static final byte ECU_ID_SID_RESPONSE = (byte) 0x5A;
|
||||
public static final byte READ_SID_GRP_RESPONSE = (byte) 0x62;
|
||||
public static final byte ECU_RESET_COMMAND = (byte) 0x04;
|
||||
public static final byte ECU_RESET_RESPONSE = (byte) 0x44;
|
||||
public static final byte NCS_NRC = (byte) 0x7F;
|
||||
public static final int RESPONSE_NON_DATA_BYTES = 3;
|
||||
public static final int ADDRESS_SIZE = 3;
|
||||
public static Module module;
|
||||
|
||||
public byte[] constructEcuFastInitRequest(Module module) {
|
||||
checkNotNull(module, "module");
|
||||
NCSProtocol.module = module;
|
||||
final byte[] request = buildRequest(
|
||||
FASTINIT_COMMAND, false, new byte[]{});
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructEcuInitRequest(Module module) {
|
||||
checkNotNull(module, "module");
|
||||
NCSProtocol.module = module;
|
||||
// len SID opt chk
|
||||
// 0x02 0x1A 0x81 0x9D
|
||||
final byte[] request = buildRequest(
|
||||
ECU_ID_SID, true, new byte[]{OPTION_81});
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadSidPidRequest(Module module, byte sid, byte[][] pid) {
|
||||
checkNotNull(module, "module");
|
||||
NCSProtocol.module = module;
|
||||
final byte[] request = buildSidPidRequest(sid, true, pid);
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
//TODO: not yet implemented
|
||||
public byte[] constructWriteMemoryRequest(
|
||||
Module module, byte[] address, byte[] values) {
|
||||
|
||||
throw new UnsupportedProtocolException(
|
||||
"Write memory command is not supported on for address: " +
|
||||
asHex(address));
|
||||
}
|
||||
|
||||
@Override
|
||||
//TODO: not yet implemented
|
||||
public byte[] constructWriteAddressRequest(
|
||||
Module module, byte[] address, byte value) {
|
||||
|
||||
throw new UnsupportedProtocolException(
|
||||
"Write Address command is not supported on for address: " +
|
||||
asHex(address));
|
||||
}
|
||||
|
||||
@Override
|
||||
//TODO: not yet implemented
|
||||
public byte[] constructReadMemoryRequest(
|
||||
Module module, byte[] address, int numBytes) {
|
||||
|
||||
throw new UnsupportedProtocolException(
|
||||
"Read memory command is not supported on for address: " +
|
||||
asHex(address));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructLoadAddressRequest(byte[][] addresses) {
|
||||
checkNotNullOrEmpty(addresses, "addresses");
|
||||
// len 0xac 0x81 fld_typ address1 [[fld_typ address2] ... [fld_typ addressN]] checksum
|
||||
return buildLoadAddrRequest(true, addresses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadAddressRequest(Module module, byte[][] addresses) {
|
||||
// read previously loaded addresses
|
||||
// len 0x21 0x81 0x04 0x01 checksum
|
||||
return buildRequest(
|
||||
READ_LOAD_COMMAND, true, new byte[]{(byte) 0x81, (byte) 0x04, (byte) 0x01});
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadAddressRequest(Module module, byte[][] bs,
|
||||
PollingState pollState) {
|
||||
byte opt_byte3;
|
||||
if (pollState.isFastPoll()) {
|
||||
// continuously read response of previously loaded addresses
|
||||
// len 0x21 0x81 0x06 0x01 checksum
|
||||
opt_byte3 = (byte) 0x06;
|
||||
}
|
||||
else {
|
||||
// read one response of previously loaded addresses
|
||||
// len 0x21 0x81 0x04 0x01 checksum
|
||||
opt_byte3 = (byte) 0x04;
|
||||
}
|
||||
return buildRequest(
|
||||
READ_LOAD_COMMAND, true, new byte[]{(byte) 0x81, opt_byte3, (byte) 0x01});
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] preprocessResponse(
|
||||
byte[] request, byte[] response, PollingState pollState) {
|
||||
return NCSResponseProcessor.filterRequestFromResponse(
|
||||
request, response, pollState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] parseResponseData(byte[] processedResponse) {
|
||||
checkNotNullOrEmpty(processedResponse, "processedResponse");
|
||||
return NCSResponseProcessor.extractResponseData(processedResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkValidEcuInitResponse(byte[] processedResponse) {
|
||||
checkNotNullOrEmpty(processedResponse, "processedResponse");
|
||||
NCSResponseProcessor.validateResponse(processedResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EcuInit parseEcuInitResponse(byte[] processedResponse) {
|
||||
checkNotNullOrEmpty(processedResponse, "processedResponse");
|
||||
//final byte[] ecuInitBytes = parseResponseData(processedResponse);
|
||||
return new NCSEcuInit(processedResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateLoadAddressResponse(byte[] response) {
|
||||
checkNotNullOrEmpty(response, "addressLoadResponse");
|
||||
NCSResponseProcessor.validateResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
//TODO: not yet implemented
|
||||
public byte[] constructEcuResetRequest(Module module, int resetCode) {
|
||||
checkNotNull(module, "module");
|
||||
NCSProtocol.module = module;
|
||||
return buildRequest((byte) 0, false, new byte[]{ECU_RESET_COMMAND});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkValidSidPidResponse(byte[] response) {
|
||||
checkNotNullOrEmpty(response, "SidPidResponse");
|
||||
NCSResponseProcessor.validateResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
//TODO: not yet implemented
|
||||
public void checkValidEcuResetResponse(byte[] processedResponse) {
|
||||
checkNotNullOrEmpty(processedResponse, "processedResponse");
|
||||
byte responseType = processedResponse[4];
|
||||
if (responseType != ECU_RESET_RESPONSE) {
|
||||
throw new InvalidResponseException(
|
||||
"Unexpected OBD Reset response: " +
|
||||
asHex(processedResponse));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkValidWriteResponse(byte[] data, byte[] processedResponse) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionProperties getDefaultConnectionProperties() {
|
||||
return new KwpConnectionProperties() {
|
||||
|
||||
public int getBaudRate() {
|
||||
return 10400;
|
||||
}
|
||||
|
||||
public void setBaudRate(int b) {
|
||||
|
||||
}
|
||||
|
||||
public int getDataBits() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
public int getStopBits() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int getParity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getConnectTimeout() {
|
||||
return 2000;
|
||||
}
|
||||
|
||||
public int getSendTimeout() {
|
||||
return 255;
|
||||
}
|
||||
|
||||
|
||||
public int getP1Max() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getP3Min() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
public int getP4Min() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final byte[] buildRequest(byte command, boolean shortHeader,
|
||||
byte[]... content) {
|
||||
|
||||
int length = 1;
|
||||
for (byte[] tmp : content) {
|
||||
length += tmp.length;
|
||||
}
|
||||
byte[] request = new byte[0];
|
||||
try {
|
||||
bb.reset();
|
||||
if (shortHeader) {
|
||||
bb.write(length);
|
||||
}
|
||||
else {
|
||||
bb.write(PHY_ADDR + length);
|
||||
bb.write(module.getAddress());
|
||||
bb.write(module.getTester());
|
||||
}
|
||||
bb.write(command);
|
||||
for (byte[] tmp : content) {
|
||||
bb.write(tmp);
|
||||
}
|
||||
bb.write((byte) 0x00);
|
||||
request = bb.toByteArray();
|
||||
final byte cs = calculateChecksum(request);
|
||||
request[request.length - 1] = cs;
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
private final byte[] buildSidPidRequest(byte command, boolean shortHeader,
|
||||
byte[]... content) {
|
||||
|
||||
int length = 3;
|
||||
for (byte[] tmp : content) {
|
||||
length += tmp.length;
|
||||
}
|
||||
byte[] request = new byte[0];
|
||||
try {
|
||||
bb.reset();
|
||||
if (shortHeader) {
|
||||
bb.write(length);
|
||||
}
|
||||
else {
|
||||
bb.write(PHY_ADDR + length);
|
||||
bb.write(module.getAddress());
|
||||
bb.write(module.getTester());
|
||||
}
|
||||
bb.write(command);
|
||||
for (byte[] tmp : content) {
|
||||
bb.write(tmp);
|
||||
}
|
||||
bb.write((byte) 0x04);
|
||||
bb.write((byte) 0x01);
|
||||
bb.write((byte) 0x00);
|
||||
request = bb.toByteArray();
|
||||
final byte cs = calculateChecksum(request);
|
||||
request[request.length - 1] = cs;
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
private final byte[] buildLoadAddrRequest(boolean shortHeader,
|
||||
byte[]... content) {
|
||||
|
||||
int length = 2;
|
||||
byte[] request = new byte[0];
|
||||
try {
|
||||
bb.reset();
|
||||
if (shortHeader) {
|
||||
bb.write(length);
|
||||
}
|
||||
else {
|
||||
bb.write(PHY_ADDR);
|
||||
bb.write(module.getAddress());
|
||||
bb.write(module.getTester());
|
||||
}
|
||||
bb.write(LOAD_ADDRESS_COMMAND);
|
||||
bb.write(OPTION_81);
|
||||
for (byte[] tmp : content) {
|
||||
if (tmp[0] == SID_21) {
|
||||
bb.write(FIELD_TYPE_01);
|
||||
bb.write(tmp, 1, tmp.length - 1);
|
||||
continue;
|
||||
}
|
||||
if (tmp[0] == SID_22) {
|
||||
bb.write(FIELD_TYPE_02);
|
||||
bb.write(tmp, 1, tmp.length - 1);
|
||||
continue;
|
||||
}
|
||||
if (tmp[0] == (byte) 0xFF) {
|
||||
bb.write(FIELD_TYPE_83);
|
||||
bb.write((byte) 0xFF);
|
||||
bb.write(tmp);
|
||||
}
|
||||
else { //assume a short length ROM address
|
||||
bb.write(FIELD_TYPE_83);
|
||||
bb.write((byte) 0x00);
|
||||
switch (tmp.length) {
|
||||
case 1:
|
||||
bb.write((byte) 0x00);
|
||||
bb.write((byte) 0x00);
|
||||
break;
|
||||
case 2:
|
||||
bb.write((byte) 0x00);
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
}
|
||||
bb.write(tmp);
|
||||
}
|
||||
}
|
||||
bb.write(0); // reserve last byte for checksum
|
||||
request = bb.toByteArray();
|
||||
if (shortHeader) {
|
||||
request[0] = (byte)(request.length - 2);
|
||||
}
|
||||
else {
|
||||
request[0] = (byte)(PHY_ADDR + request.length - 4);
|
||||
}
|
||||
final byte cs = calculateChecksum(request);
|
||||
request[request.length - 1] = cs;
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return request;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.io.protocol.ncs.iso14230;
|
||||
|
||||
import static com.romraider.io.protocol.ncs.iso14230.NCSChecksumCalculator.calculateChecksum;
|
||||
import static com.romraider.io.protocol.ncs.iso14230.NCSProtocol.LOAD_ADDRESS_RESPONSE;
|
||||
import static com.romraider.io.protocol.ncs.iso14230.NCSProtocol.ECU_ID_SID_RESPONSE;
|
||||
import static com.romraider.io.protocol.ncs.iso14230.NCSProtocol.NCS_NRC;
|
||||
import static com.romraider.io.protocol.ncs.iso14230.NCSProtocol.READ_LOAD_RESPONSE;
|
||||
import static com.romraider.io.protocol.ncs.iso14230.NCSProtocol.RESPONSE_NON_DATA_BYTES;
|
||||
import static com.romraider.io.protocol.ncs.iso14230.NCSProtocol.READ_SID_GRP_RESPONSE;
|
||||
import static com.romraider.util.ByteUtil.asUnsignedInt;
|
||||
import static com.romraider.util.HexUtil.asHex;
|
||||
import static com.romraider.util.ParamChecker.checkNotNullOrEmpty;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.romraider.logger.ecu.comms.manager.PollingState;
|
||||
import com.romraider.logger.ecu.exception.InvalidResponseException;
|
||||
|
||||
public final class NCSResponseProcessor {
|
||||
|
||||
private NCSResponseProcessor() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public final static byte[] filterRequestFromResponse(
|
||||
byte[] request, byte[] response, PollingState pollState) {
|
||||
checkNotNullOrEmpty(response, "response");
|
||||
// If J2534 device Loopback is off, the request is filtered out by J2534 device
|
||||
// and only the response is present
|
||||
return response;
|
||||
}
|
||||
|
||||
public final static void validateResponse(byte[] response) {
|
||||
checkNotNullOrEmpty(response, "response");
|
||||
assertTrue(response.length > RESPONSE_NON_DATA_BYTES,
|
||||
"Invalid response length");
|
||||
validateChecksum(response);
|
||||
if (response[1] == NCS_NRC) {
|
||||
assertNrc((byte) (response[2] + 0x40), response[1], response[2], response[3],
|
||||
"Request type not supported");
|
||||
}
|
||||
assertOneOf(new byte[]{ECU_ID_SID_RESPONSE, LOAD_ADDRESS_RESPONSE,
|
||||
READ_LOAD_RESPONSE, READ_SID_GRP_RESPONSE},
|
||||
response[1], "Invalid response code");
|
||||
}
|
||||
|
||||
public final static byte[] extractResponseData(byte[] response) {
|
||||
checkNotNullOrEmpty(response, "response");
|
||||
// len response_sid option response_data1 ... [response_dataN]
|
||||
validateResponse(response);
|
||||
final byte[] data = new byte[response.length - 4];
|
||||
System.arraycopy(response, RESPONSE_NON_DATA_BYTES, data, 0, data.length);
|
||||
return data;
|
||||
}
|
||||
|
||||
private final static void validateChecksum(byte[] response) {
|
||||
final byte calc_chk = calculateChecksum(response);
|
||||
final byte pkt_cs = response[response.length - 1];
|
||||
assertTrue(calc_chk == pkt_cs, String.format(
|
||||
"Response checksum match failure. Expected: %s, Actual: %s",
|
||||
asHex(calc_chk), asHex(pkt_cs)));
|
||||
}
|
||||
|
||||
private final static void assertTrue(boolean condition, String msg) {
|
||||
if (!condition) {
|
||||
throw new InvalidResponseException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private final static void assertNrc(
|
||||
byte expected, byte actual, byte command, byte code, String msg) {
|
||||
|
||||
if (actual == expected) {
|
||||
String ec = "unsupported.";
|
||||
if (code == 0x10) {
|
||||
ec = "general reject no specific reason.";
|
||||
}
|
||||
if (code == 0x12) {
|
||||
ec = "request sub-function is not supported or invalid format.";
|
||||
}
|
||||
if (code == 0x13) {
|
||||
ec = "invalid format or length.";
|
||||
}
|
||||
if (code == 0x21) {
|
||||
ec = "busy, repeat request.";
|
||||
}
|
||||
if (code == 0x22) {
|
||||
ec = "conditions not correct or request sequence error.";
|
||||
}
|
||||
throw new InvalidResponseException(String.format(
|
||||
"%s. Command: %s, %s",
|
||||
msg, asHex(command), ec));
|
||||
}
|
||||
}
|
||||
|
||||
private final static void assertOneOf(
|
||||
byte[] validOptions, byte actual, String msg) {
|
||||
|
||||
for (byte option : validOptions) {
|
||||
if (option == actual) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < validOptions.length; i++) {
|
||||
if (i > 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append(asHex(validOptions[i]));
|
||||
}
|
||||
throw new InvalidResponseException(String.format(
|
||||
"%s. Expected one of [%s]. Actual: %s.",
|
||||
msg, builder.toString(), asHex(actual)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.logger.ecu.comms.io.connection;
|
||||
|
||||
import static com.romraider.util.HexUtil.asHex;
|
||||
import static com.romraider.util.ParamChecker.checkNotNull;
|
||||
import static com.romraider.util.ThreadUtil.sleep;
|
||||
import static org.apache.log4j.Logger.getLogger;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.romraider.Settings;
|
||||
import com.romraider.util.SettingsManager;
|
||||
import com.romraider.io.connection.ConnectionManager;
|
||||
import com.romraider.io.protocol.ProtocolFactory;
|
||||
import com.romraider.logger.ecu.comms.io.protocol.LoggerProtocolNCS;
|
||||
import com.romraider.logger.ecu.comms.manager.PollingState;
|
||||
import com.romraider.logger.ecu.comms.manager.PollingStateImpl;
|
||||
import com.romraider.logger.ecu.comms.query.EcuInitCallback;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQuery;
|
||||
import com.romraider.logger.ecu.definition.Module;
|
||||
import com.romraider.logger.ecu.exception.SerialCommunicationException;
|
||||
|
||||
public final class NCSLoggerConnection implements LoggerConnection {
|
||||
private static final Logger LOGGER = getLogger(NCSLoggerConnection.class);
|
||||
private final LoggerProtocolNCS protocol;
|
||||
private final ConnectionManager manager;
|
||||
private int queryCount;
|
||||
|
||||
public NCSLoggerConnection(ConnectionManager manager) {
|
||||
checkNotNull(manager, "manager");
|
||||
this.manager = manager;
|
||||
final Settings settings = SettingsManager.getSettings();
|
||||
this.protocol = (LoggerProtocolNCS) ProtocolFactory.getProtocol(
|
||||
settings.getLoggerProtocol(),
|
||||
settings.getTransportProtocol());
|
||||
}
|
||||
|
||||
@Override
|
||||
//TODO: not yet implemented
|
||||
public void ecuReset(Module module, int resetCode) {
|
||||
byte[] request = protocol.constructEcuResetRequest(module, resetCode);
|
||||
LOGGER.debug(String.format("%s Reset Request ---> %s",
|
||||
module, asHex(request)));
|
||||
byte[] response = manager.send(request);
|
||||
byte[] processedResponse = protocol.preprocessResponse(
|
||||
request, response, new PollingStateImpl());
|
||||
LOGGER.debug(String.format("%s Reset Response <--- %s",
|
||||
module, asHex(processedResponse)));
|
||||
protocol.processEcuResetResponse(processedResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
// Build an init string similar to the SSM version so the logger definition
|
||||
// can reference supported parameters with ecubyte/bit attributes.
|
||||
public void ecuInit(EcuInitCallback callback, Module module) {
|
||||
final byte[] initResponse = new byte[422];
|
||||
byte[] request = protocol.constructEcuInitRequest(module);
|
||||
LOGGER.debug(String.format("%s ID Request ---> %s",
|
||||
module, asHex(request)));
|
||||
byte[] response = new byte[9];
|
||||
manager.send(request, response, new PollingStateImpl());
|
||||
LOGGER.debug(String.format("%s ID Response <--- %s",
|
||||
module, asHex(response)));
|
||||
System.arraycopy(response, 0, initResponse, 0, response.length - 1);
|
||||
sleep(55L);
|
||||
|
||||
final byte[] supportedPidsPid = {
|
||||
(byte) 0x00, (byte) 0x20, (byte) 0x40, (byte) 0x60,
|
||||
(byte) 0x80, (byte) 0xA0, (byte) 0xC0, (byte) 0xE0};
|
||||
int i = 8;
|
||||
byte sid = (byte) 0x21;
|
||||
boolean test_grp = true;
|
||||
for (byte pid : supportedPidsPid) {
|
||||
if (test_grp) {
|
||||
request = protocol.constructReadSidPidRequest(
|
||||
module, sid, new byte[]{pid});
|
||||
LOGGER.debug(String.format("%s SID %02X, PID Group %02X Request ---> %s",
|
||||
module, sid, pid, asHex(request)));
|
||||
response = new byte[8];
|
||||
manager.send(request, response, new PollingStateImpl());
|
||||
LOGGER.debug(String.format("%s SID %02X, PID Group %02X Response <--- %s",
|
||||
module, sid ,pid, asHex(response)));
|
||||
// Validate response
|
||||
protocol.processReadSidPidResponse(response);
|
||||
System.arraycopy(response, 3, initResponse, i, 4);
|
||||
// Check lsb to see if next PID group is supported
|
||||
if ((response[response[0]] & 0x01) == 0) {
|
||||
test_grp = false;
|
||||
}
|
||||
}
|
||||
i = i + 4;
|
||||
}
|
||||
sid = (byte) 0x22;
|
||||
final byte[] highBytes = {
|
||||
(byte) 0x11, (byte) 0x12, (byte) 0x13, (byte) 0x14,
|
||||
(byte) 0x15};
|
||||
for (byte hb : highBytes) {
|
||||
if (hb == (byte) 0x13) {
|
||||
test_grp = true;
|
||||
for (byte pid : supportedPidsPid) {
|
||||
if (test_grp) {
|
||||
request = protocol.constructReadSidPidRequest(
|
||||
module, sid, new byte[]{hb, pid});
|
||||
LOGGER.debug(String.format("%s SID %02X, PID Group %02X%02X Request ---> %s",
|
||||
module, sid, hb, pid, asHex(request)));
|
||||
response = new byte[9];
|
||||
manager.send(request, response, new PollingStateImpl());
|
||||
LOGGER.debug(String.format("%s SID %02X, PID Group %02X%02X Response <--- %s",
|
||||
module, sid ,hb, pid, asHex(response)));
|
||||
// Validate response
|
||||
protocol.processReadSidPidResponse(response);
|
||||
// Check lsb to see if next PID group is supported
|
||||
if ((response[response[0]] & 0x01) == 0) {
|
||||
test_grp = false;
|
||||
}
|
||||
final short[] supported = new short[2];
|
||||
for (int j = 0; j < 2; j++) {
|
||||
supported[j] = (short) ((short)(response[j*2+4] << 8) + ((short)response[j*2+5] & 0x00FF));
|
||||
}
|
||||
for (int k = 0; k < supported.length; k++) {
|
||||
// ex: 7FFC2000
|
||||
for (int shift = 15; shift > -1; shift--) {
|
||||
if (((1 << shift) & supported[k]) > 0) {
|
||||
byte cid = (byte) ((16 - shift) + (k * 16));
|
||||
request = protocol.constructReadSidPidRequest(
|
||||
module, sid, new byte[]{hb, cid});
|
||||
LOGGER.debug(String.format("%s SID %02X, PID %02X%02X Request ---> %s",
|
||||
module, sid, hb, cid, asHex(request)));
|
||||
response = new byte[7];
|
||||
manager.send(request, response, new PollingStateImpl());
|
||||
LOGGER.debug(String.format("%s SID %02X, PID %02X%02X Response <--- %s",
|
||||
module, sid ,hb, cid, asHex(response)));
|
||||
// Validate response
|
||||
protocol.processReadSidPidResponse(response);
|
||||
System.arraycopy(response, 5, initResponse, i, 1);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
i = i + 32;
|
||||
}
|
||||
}
|
||||
i--; // move back one unused index byte position
|
||||
}
|
||||
else {
|
||||
test_grp = true;
|
||||
for (byte pid : supportedPidsPid) {
|
||||
if (test_grp) {
|
||||
request = protocol.constructReadSidPidRequest(
|
||||
module, sid, new byte[]{hb, pid});
|
||||
LOGGER.debug(String.format("%s SID %02X, PID Group %02X%02X Request ---> %s",
|
||||
module, sid, hb, pid, asHex(request)));
|
||||
response = new byte[9];
|
||||
manager.send(request, response, new PollingStateImpl());
|
||||
LOGGER.debug(String.format("%s SID %02X, PID Group %02X%02X Response <--- %s",
|
||||
module, sid ,hb, pid, asHex(response)));
|
||||
// Validate response
|
||||
protocol.processReadSidPidResponse(response);
|
||||
System.arraycopy(response, 4, initResponse, i, 4);
|
||||
// Check lsb to see if next PID group is supported
|
||||
if ((response[response[0]] & 0x01) == 0) {
|
||||
test_grp = false;
|
||||
}
|
||||
}
|
||||
i = i + 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOGGER.debug(String.format("%s Init Response <--- %s",
|
||||
module, asHex(initResponse))); // contains ECUID
|
||||
protocol.processEcuInitResponse(callback, initResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void sendAddressReads(
|
||||
Collection<EcuQuery> queries,
|
||||
Module module,
|
||||
PollingState pollState) {
|
||||
|
||||
if (queries.size() != queryCount
|
||||
|| pollState.isNewQuery()) {
|
||||
// max data bytes 255 including TX loopback
|
||||
int dataLength = 0;
|
||||
for (EcuQuery query : queries) {
|
||||
dataLength += query.getBytes().length;
|
||||
}
|
||||
// if length is too big then notify user to un-select some parameters
|
||||
if (dataLength > 60) {
|
||||
throw new SerialCommunicationException(
|
||||
"Request message too large, un-select some parameters");
|
||||
}
|
||||
final byte[] request = protocol.constructLoadAddressRequest(queries);
|
||||
LOGGER.debug(String.format("Mode:%s %s Load address request ---> %s",
|
||||
pollState.getCurrentState(), module, asHex(request)));
|
||||
|
||||
final byte[] response = new byte[4];
|
||||
manager.send(request, response, pollState);
|
||||
LOGGER.debug(String.format("Mode:%s %s Load address response <--- %s",
|
||||
pollState.getCurrentState(), module, asHex(response)));
|
||||
protocol.validateLoadAddressResponse(response);
|
||||
queryCount = queries.size();
|
||||
}
|
||||
final byte[] request = protocol.constructReadAddressRequest(
|
||||
module, queries, pollState);
|
||||
if (pollState.getCurrentState() == PollingState.State.STATE_0) {
|
||||
LOGGER.debug(String.format("Mode:%s %s Read request ---> %s",
|
||||
pollState.getCurrentState(), module, asHex(request)));
|
||||
pollState.setLastState(PollingState.State.STATE_0);
|
||||
}
|
||||
final byte[] response = protocol.constructReadAddressResponse(
|
||||
queries, pollState);
|
||||
manager.send(request, response, pollState);
|
||||
LOGGER.debug(String.format("Mode:%s %s Read response <--- %s",
|
||||
pollState.getCurrentState(), module, asHex(response)));
|
||||
protocol.processReadAddressResponses(
|
||||
queries, response, pollState);
|
||||
}
|
||||
|
||||
public void clearQueryCount() {
|
||||
queryCount = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearLine() {
|
||||
clearQueryCount();
|
||||
manager.clearLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
clearQueryCount();
|
||||
manager.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAddressWrites(Map<EcuQuery, byte[]> writeQueries, Module module) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.logger.ecu.comms.io.protocol;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.romraider.logger.ecu.comms.manager.PollingState;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQuery;
|
||||
import com.romraider.logger.ecu.definition.Module;
|
||||
|
||||
|
||||
public interface LoggerProtocolNCS extends LoggerProtocol {
|
||||
|
||||
byte[] constructEcuFastInitRequest(Module module);
|
||||
|
||||
byte[] constructReadSidPidRequest(Module module, byte sid, byte[] pid);
|
||||
|
||||
byte[] constructLoadAddressRequest(Collection<EcuQuery> queries);
|
||||
|
||||
void validateLoadAddressResponse(byte[] response);
|
||||
|
||||
void processReadSidPidResponse(byte[] response);
|
||||
|
||||
byte[] constructReadAddressRequest(Module module,
|
||||
Collection<EcuQuery> queries, PollingState pollState);
|
||||
}
|
|
@ -0,0 +1,620 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.logger.ecu.comms.learning;
|
||||
|
||||
import static com.romraider.logger.ecu.comms.io.connection.LoggerConnectionFactory.getConnection;
|
||||
import static javax.swing.JOptionPane.ERROR_MESSAGE;
|
||||
import static javax.swing.JOptionPane.WARNING_MESSAGE;
|
||||
import static javax.swing.JOptionPane.showMessageDialog;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import com.romraider.Settings;
|
||||
import com.romraider.logger.ecu.EcuLogger;
|
||||
import com.romraider.logger.ecu.comms.io.connection.LoggerConnection;
|
||||
import com.romraider.logger.ecu.comms.learning.parameter.NCSParameter;
|
||||
import com.romraider.logger.ecu.comms.learning.parameter.NCSParameterCrossReference;
|
||||
import com.romraider.logger.ecu.comms.learning.parameter.ParameterIdComparator;
|
||||
import com.romraider.logger.ecu.comms.learning.tableaxis.NCSTableAxisQueryParameterSet;
|
||||
import com.romraider.logger.ecu.comms.learning.tables.NCSLtftTableQueryBuilder;
|
||||
import com.romraider.logger.ecu.comms.manager.PollingStateImpl;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQuery;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQueryImpl;
|
||||
import com.romraider.logger.ecu.definition.EcuData;
|
||||
import com.romraider.logger.ecu.definition.EcuDefinition;
|
||||
import com.romraider.logger.ecu.definition.Module;
|
||||
import com.romraider.logger.ecu.definition.Transport;
|
||||
import com.romraider.logger.ecu.definition.xml.EcuDefinitionDocumentLoader;
|
||||
import com.romraider.logger.ecu.definition.xml.EcuDefinitionInheritanceList;
|
||||
import com.romraider.logger.ecu.definition.xml.EcuTableDefinitionHandler;
|
||||
import com.romraider.logger.ecu.ui.MessageListener;
|
||||
import com.romraider.logger.ecu.ui.paramlist.ParameterListTableModel;
|
||||
import com.romraider.logger.ecu.ui.paramlist.ParameterRow;
|
||||
import com.romraider.logger.ecu.ui.swing.tools.NCSLearningTableValuesResultsPanel;
|
||||
import com.romraider.util.ParamChecker;
|
||||
|
||||
|
||||
/**
|
||||
* This class manages the building of ECU queries and retrieving the data to
|
||||
* populate the table models which will be used by the Learning Table Values
|
||||
* display panel.
|
||||
*/
|
||||
public final class NCSLearningTableValues extends SwingWorker<Void, Void>
|
||||
implements LearningTableValues {
|
||||
|
||||
private static final Logger LOGGER =
|
||||
Logger.getLogger(NCSLearningTableValues.class);
|
||||
private static final List<String> AF_TABLE_NAMES = Arrays.asList(
|
||||
"A/F Learning #1 Airflow Ranges",
|
||||
"A/F Learning #1 Airflow Ranges ",
|
||||
"A/F Learning Airflow Ranges");
|
||||
// LTFT table column and row names can be overridden in the
|
||||
// ./customize/ncslearning.properties file
|
||||
private static List<String> LTFT_TABLE_COLUMN_NAMES = Arrays.asList(
|
||||
"Learning map TP shaft lattice point table");
|
||||
private static List<String> LTFT_TABLE_ROW_NAMES = Arrays.asList(
|
||||
"Learning map N shaft lattice point table");
|
||||
private final Map<String, Object> vehicleInfo =
|
||||
new LinkedHashMap<String, Object>();
|
||||
private final List<List<Object>> afLearning = new ArrayList<List<Object>>();
|
||||
private EcuLogger logger;
|
||||
private Settings settings;
|
||||
private MessageListener messageListener;
|
||||
private ParameterListTableModel parmeterList;
|
||||
private EcuDefinition ecuDef;
|
||||
private ParameterRow ltftTrim;
|
||||
private int ltftTrimAddr;
|
||||
private ParameterRow ltftCnt;
|
||||
private int ltftCntAddr;
|
||||
|
||||
public NCSLearningTableValues() {}
|
||||
|
||||
public void init(
|
||||
EcuLogger logger,
|
||||
ParameterListTableModel dataTabParamListTableModel,
|
||||
EcuDefinition ecuDef) {
|
||||
|
||||
ParamChecker.checkNotNull(logger, "EcuLogger");
|
||||
ParamChecker.checkNotNull(dataTabParamListTableModel,
|
||||
"ParameterListTableModel");
|
||||
this.logger = logger;
|
||||
this.settings = logger.getSettings();
|
||||
this.messageListener = logger;
|
||||
this.parmeterList = dataTabParamListTableModel;
|
||||
this.ecuDef = ecuDef;
|
||||
this.ltftTrim = null;
|
||||
this.ltftTrimAddr = 0;
|
||||
this.ltftCnt = null;
|
||||
this.ltftCntAddr = 0;
|
||||
loadProperties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Void doInBackground() {
|
||||
Document document = null;
|
||||
if (ecuDef.getEcuDefFile() == null) {
|
||||
showMessageDialog(logger,
|
||||
"ECU definition file not found or undefined. Learning\n" +
|
||||
"Table Values cannot be properly retrieved until an ECU\n" +
|
||||
"defintion is defined in the Editor's Definition Manager.",
|
||||
"ECU Defintion Missing", WARNING_MESSAGE);
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
document = EcuDefinitionDocumentLoader.getDocument(ecuDef);
|
||||
}
|
||||
|
||||
final String transport = settings.getTransportProtocol();
|
||||
final Module module = settings.getDestinationTarget();
|
||||
if (settings.isCanBus()) {
|
||||
settings.setTransportProtocol("ISO14230");
|
||||
final Module ecuModule = getModule("ECU");
|
||||
settings.setDestinationTarget(ecuModule);
|
||||
}
|
||||
final boolean logging = logger.isLogging();
|
||||
if (logging) logger.stopLogging();
|
||||
|
||||
String message = "Retrieving vehicle info & LTFT values...";
|
||||
messageListener.reportMessage(message);
|
||||
buildVehicleInfoMap(ecuDef);
|
||||
|
||||
try {
|
||||
LoggerConnection connection = getConnection(
|
||||
settings.getLoggerProtocol(), settings.getLoggerPort(),
|
||||
settings.getLoggerConnectionProperties());
|
||||
try {
|
||||
Collection<EcuQuery> queries = buildLearningQueries();
|
||||
// Break queries into two sets to avoid the ECU packet limit
|
||||
int setSize = queries.size() / 2;
|
||||
Collection<EcuQuery> querySet1 = new ArrayList<EcuQuery>();
|
||||
Collection<EcuQuery> querySet2 = new ArrayList<EcuQuery>();
|
||||
int s = 0;
|
||||
for (EcuQuery q : queries) {
|
||||
if (s < setSize) {
|
||||
querySet1.add(q);
|
||||
}
|
||||
else {
|
||||
querySet2.add(q);
|
||||
}
|
||||
s++;
|
||||
}
|
||||
LOGGER.trace(
|
||||
String.format(
|
||||
"Queries:%d, Set size:%d, Set 1 size:%d, Set 2 size:%d",
|
||||
queries.size(), setSize, querySet1.size(), querySet2.size()));
|
||||
|
||||
LOGGER.info(message);
|
||||
connection.sendAddressReads(
|
||||
querySet1,
|
||||
settings.getDestinationTarget(),
|
||||
new PollingStateImpl());
|
||||
connection.sendAddressReads(
|
||||
querySet2,
|
||||
settings.getDestinationTarget(),
|
||||
new PollingStateImpl());
|
||||
LOGGER.info("Current vehicle info & LTFT values retrieved.");
|
||||
|
||||
Collections.sort(
|
||||
(List<EcuQuery>)queries, new ParameterIdComparator());
|
||||
|
||||
processEcuQueryResponses((List<EcuQuery>) queries);
|
||||
|
||||
//TODO: afRanges to be replaced with Knock tables once known how they operate
|
||||
String[] afRanges = new String[0];
|
||||
|
||||
message = "Retrieving LTFT column ranges...";
|
||||
messageListener.reportMessage(message);
|
||||
String[] ltftCol = new String[0];
|
||||
queries.clear();
|
||||
queries = getTableAxisRanges(document, ecuDef, LTFT_TABLE_COLUMN_NAMES);
|
||||
if (queries != null && !queries.isEmpty()) {
|
||||
LOGGER.info(message);
|
||||
connection.sendAddressReads(
|
||||
queries,
|
||||
settings.getDestinationTarget(),
|
||||
new PollingStateImpl());
|
||||
LOGGER.info("LTFT column ranges retrieved.");
|
||||
ltftCol = formatRanges(queries, "%.2f");
|
||||
}
|
||||
|
||||
message = "Retrieving LTFT row ranges...";
|
||||
messageListener.reportMessage(message);
|
||||
String[] ltftRow = new String[0];
|
||||
queries.clear();
|
||||
queries = getTableAxisRanges(document, ecuDef, LTFT_TABLE_ROW_NAMES);
|
||||
if (queries != null && !queries.isEmpty()) {
|
||||
LOGGER.info(message);
|
||||
connection.sendAddressReads(
|
||||
queries,
|
||||
settings.getDestinationTarget(),
|
||||
new PollingStateImpl());
|
||||
LOGGER.info("LTFT row ranges retrieved.");
|
||||
ltftRow = formatRpmRanges(queries);
|
||||
}
|
||||
|
||||
List<List<List<EcuQuery>>> ltftQueryTables = new ArrayList<List<List<EcuQuery>>>();
|
||||
List<List<EcuQuery>> ltftQueryGroups = new ArrayList<List<EcuQuery>>();
|
||||
if (ltftTrim != null) {
|
||||
for (int k = 0; k < 256; k += 128) {
|
||||
ltftQueryGroups = new NCSLtftTableQueryBuilder().build(
|
||||
ltftTrim,
|
||||
ltftTrimAddr + k,
|
||||
ltftRow.length,
|
||||
ltftCol.length - 1);
|
||||
ltftQueryTables.add(ltftQueryGroups);
|
||||
|
||||
for (int i = 0; i < ltftQueryGroups.size(); i++) {
|
||||
queries.clear();
|
||||
for (int j = 0; j < ltftQueryGroups.get(i).size(); j++) {
|
||||
if (ltftQueryGroups.get(i).get(j) != null) {
|
||||
queries.add(ltftQueryGroups.get(i).get(j));
|
||||
}
|
||||
}
|
||||
message = String.format(
|
||||
"Retrieving Table %d LTFT row %d values...",
|
||||
(k/128+1), i);
|
||||
messageListener.reportMessage(message);
|
||||
LOGGER.info(message);
|
||||
setSize = queries.size() / 2;
|
||||
querySet1 = new ArrayList<EcuQuery>();
|
||||
querySet2 = new ArrayList<EcuQuery>();
|
||||
s = 0;
|
||||
for (EcuQuery q : queries) {
|
||||
if (s < setSize) {
|
||||
querySet1.add(q);
|
||||
}
|
||||
else {
|
||||
querySet2.add(q);
|
||||
}
|
||||
s++;
|
||||
}
|
||||
LOGGER.trace(
|
||||
String.format(
|
||||
"Queries:%d, Set size:%d, Set 1 size:%d, Set 2 size:%d",
|
||||
queries.size(), setSize, querySet1.size(), querySet2.size()));
|
||||
|
||||
LOGGER.info(message);
|
||||
connection.sendAddressReads(
|
||||
querySet1,
|
||||
settings.getDestinationTarget(),
|
||||
new PollingStateImpl());
|
||||
connection.sendAddressReads(
|
||||
querySet2,
|
||||
settings.getDestinationTarget(),
|
||||
new PollingStateImpl());
|
||||
LOGGER.info(String.format(
|
||||
"Table %d row %d LTFT values retrieved.",
|
||||
(k/128+1), i));
|
||||
queries.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
message = String.format(
|
||||
"Error retrieving LTFT data values, missing LTFT reference");
|
||||
messageListener.reportMessage(message);
|
||||
LOGGER.error(message);
|
||||
}
|
||||
if (ltftCnt != null) {
|
||||
for (int k = 0; k < 128; k += 64) {
|
||||
ltftQueryGroups = new NCSLtftTableQueryBuilder().build(
|
||||
ltftCnt,
|
||||
ltftCntAddr + k,
|
||||
ltftRow.length,
|
||||
ltftCol.length - 1);
|
||||
ltftQueryTables.add(ltftQueryGroups);
|
||||
|
||||
for (int i = 0; i < ltftQueryGroups.size(); i++) {
|
||||
queries.clear();
|
||||
for (int j = 0; j < ltftQueryGroups.get(i).size(); j++) {
|
||||
if (ltftQueryGroups.get(i).get(j) != null) {
|
||||
queries.add(ltftQueryGroups.get(i).get(j));
|
||||
}
|
||||
}
|
||||
message = String.format("Retrieving Table %d LTFT row %d values...",
|
||||
(k/64+3), i);
|
||||
messageListener.reportMessage(message);
|
||||
LOGGER.info(message);
|
||||
setSize = queries.size() / 2;
|
||||
querySet1 = new ArrayList<EcuQuery>();
|
||||
querySet2 = new ArrayList<EcuQuery>();
|
||||
s = 0;
|
||||
for (EcuQuery q : queries) {
|
||||
if (s < setSize) {
|
||||
querySet1.add(q);
|
||||
}
|
||||
else {
|
||||
querySet2.add(q);
|
||||
}
|
||||
s++;
|
||||
}
|
||||
LOGGER.trace(
|
||||
String.format("Queries:%d, Set size:%d, Set 1 size:%d, Set 2 size:%d",
|
||||
queries.size(), setSize, querySet1.size(), querySet2.size()));
|
||||
|
||||
LOGGER.info(message);
|
||||
connection.sendAddressReads(
|
||||
querySet1,
|
||||
settings.getDestinationTarget(),
|
||||
new PollingStateImpl());
|
||||
connection.sendAddressReads(
|
||||
querySet2,
|
||||
settings.getDestinationTarget(),
|
||||
new PollingStateImpl());
|
||||
LOGGER.info(String.format("Table %d row %d LTFT values retrieved.",
|
||||
(k/64+3), i));
|
||||
queries.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
message = String.format("Error retrieving LTFT data values, missing LTFT reference");
|
||||
messageListener.reportMessage(message);
|
||||
LOGGER.error(message);
|
||||
}
|
||||
|
||||
messageListener.reportMessage(
|
||||
"Learning Table Values retrieved successfully.");
|
||||
final NCSLearningTableValuesResultsPanel results =
|
||||
new NCSLearningTableValuesResultsPanel(
|
||||
logger, vehicleInfo,
|
||||
afRanges, afLearning,
|
||||
ltftCol, ltftRow, ltftQueryTables);
|
||||
results.displayLearningResultsPanel();
|
||||
}
|
||||
finally {
|
||||
connection.close();
|
||||
settings.setTransportProtocol(transport);
|
||||
settings.setDestinationTarget(module);
|
||||
if (logging) logger.startLogging();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
messageListener.reportError(
|
||||
"Unable to retrieve current ECU learning values");
|
||||
LOGGER.error(message + " Error retrieving values", e);
|
||||
showMessageDialog(logger,
|
||||
message +
|
||||
"\nError performing Learning Table Values read.\n" +
|
||||
"Check the following:\n" +
|
||||
"* Logger has successfully conencted to the ECU\n" +
|
||||
"* Correct COM port is selected (if not Openport 2)\n" +
|
||||
"* Cable is connected properly\n* Ignition is ON\n",
|
||||
"Learning Table Values",
|
||||
ERROR_MESSAGE);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a collection of queries based on the initialized values of
|
||||
* parameters defined for this ECU. Also identify the LTFT Trim and Count
|
||||
* parameters used to locate the LTFT tables.
|
||||
* @return the supported parameter list filtered for only the Learning Table
|
||||
* Value parameters needed.
|
||||
*/
|
||||
private final Collection<EcuQuery> buildLearningQueries() {
|
||||
final Collection<EcuQuery> query = new ArrayList<EcuQuery>();
|
||||
final List<ParameterRow> parameterRows = parmeterList.getParameterRows();
|
||||
if (!ParamChecker.isNullOrEmpty(parameterRows)) {
|
||||
for (ParameterRow parameterRow : parameterRows) {
|
||||
final NCSParameter parameterId =
|
||||
NCSParameter.fromValue(parameterRow.getLoggerData().getId());
|
||||
if (parameterId != null) {
|
||||
switch (parameterId) {
|
||||
case E173:
|
||||
ltftTrimAddr = getParameterAddr(parameterRow);
|
||||
ltftTrim = parameterRow;
|
||||
break;
|
||||
case E174:
|
||||
ltftCntAddr = getParameterAddr(parameterRow);
|
||||
ltftCnt = parameterRow;
|
||||
break;
|
||||
default:
|
||||
query.add(buildEcuQuery(parameterRow));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a query object for a parameter item.
|
||||
* @return a new EcuQuery.
|
||||
*/
|
||||
private final EcuQuery buildEcuQuery(ParameterRow parameterRow) {
|
||||
final EcuQuery ecuQuery =
|
||||
new EcuQueryImpl((EcuData) parameterRow.getLoggerData());
|
||||
return ecuQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parameter's integer address.
|
||||
*/
|
||||
private final int getParameterAddr(ParameterRow parameterRow) {
|
||||
final EcuData ecudata = (EcuData) parameterRow.getLoggerData();
|
||||
final String addrStr = ecudata.getAddress().getAddresses()[0];
|
||||
final String addrHexStr = addrStr.replaceAll("0x", "");
|
||||
return Integer.parseInt(addrHexStr, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start populating the vehicle information map with passed values.
|
||||
*/
|
||||
private final void buildVehicleInfoMap(EcuDefinition ecuDef) {
|
||||
vehicleInfo.put("CAL ID", ecuDef.getCalId());
|
||||
vehicleInfo.put("ECU ID", ecuDef.getEcuId());
|
||||
vehicleInfo.put("Description",
|
||||
ecuDef.getCarString().replaceAll("Nissan ", ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the table axis values from the ECU definition. First try the
|
||||
* 4-cyl table names, if still empty try the 6-cyl table name.
|
||||
*/
|
||||
private final List<EcuQuery> getTableAxisRanges(
|
||||
Document document,
|
||||
EcuDefinition ecuDef,
|
||||
List<String> tableNames) {
|
||||
|
||||
List<EcuQuery> tableAxis = new ArrayList<EcuQuery>();
|
||||
for (String tableName : tableNames) {
|
||||
tableAxis = loadTable(document, ecuDef, tableName);
|
||||
if (!tableAxis.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return tableAxis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Once values from the ECU have been populated add the values to the
|
||||
* table models datasets.
|
||||
*/
|
||||
private final void processEcuQueryResponses(List<EcuQuery> queries) {
|
||||
final NCSParameterCrossReference parameterMap = new NCSParameterCrossReference();
|
||||
|
||||
for (EcuQuery query : queries) {
|
||||
final NCSParameter parameterId =
|
||||
NCSParameter.fromValue(query.getLoggerData().getId());
|
||||
final String paramDesc = parameterMap.getValue(parameterId);
|
||||
String result = String.format("%.2f %s",
|
||||
query.getResponse(),
|
||||
query.getLoggerData().getSelectedConvertor().getUnits());
|
||||
switch (parameterId) {
|
||||
default:
|
||||
vehicleInfo.put(paramDesc, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a List of EcuQueries to retrieve the axis and scaling of a table.
|
||||
* A table is found when the storageaddress parameter has been identified.
|
||||
*/
|
||||
private final List<EcuQuery> loadTable(
|
||||
Document document,
|
||||
EcuDefinition ecuDef,
|
||||
String tableName) {
|
||||
|
||||
final List<Node> inheritanceList =
|
||||
EcuDefinitionInheritanceList.getInheritanceList(document, ecuDef);
|
||||
final Map<String, String> tableMap =
|
||||
EcuTableDefinitionHandler.getTableDefinition(
|
||||
document,
|
||||
inheritanceList,
|
||||
tableName);
|
||||
List<EcuQuery> tableAxisQuery = new ArrayList<EcuQuery>();
|
||||
if (tableMap.containsKey("storageaddress")) {
|
||||
tableAxisQuery = NCSTableAxisQueryParameterSet.build(
|
||||
tableMap.get("storageaddress"),
|
||||
tableMap.get("storagetype"),
|
||||
tableMap.get("expression"),
|
||||
tableMap.get("units"),
|
||||
tableMap.get("sizey")
|
||||
);
|
||||
}
|
||||
return tableAxisQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the range data to be used as table column header values.
|
||||
*/
|
||||
private final String[] formatRanges(
|
||||
Collection<EcuQuery> axisRanges,
|
||||
String numberFormat) {
|
||||
|
||||
final List<String> ranges = new ArrayList<String>();
|
||||
ranges.add(" ");
|
||||
double value = 0;
|
||||
for (EcuQuery ecuQuery : axisRanges) {
|
||||
value = ecuQuery.getResponse();
|
||||
final String range = String.format(
|
||||
numberFormat,
|
||||
value);
|
||||
ranges.add(range);
|
||||
}
|
||||
return ranges.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the RPM range data to be used as FLKC table row header values.
|
||||
*/
|
||||
private final String[] formatRpmRanges(Collection<EcuQuery> axisRanges) {
|
||||
|
||||
final List<String> ranges = new ArrayList<String>();
|
||||
double value = 0;
|
||||
for (EcuQuery ecuQuery : axisRanges) {
|
||||
value = ecuQuery.getResponse();
|
||||
final String range = String.format(
|
||||
"%.0f", value);
|
||||
ranges.add(range);
|
||||
}
|
||||
return ranges.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Transport based on its String ID.
|
||||
*/
|
||||
private Transport getTransportById(String id) {
|
||||
for (Transport transport : getTransportMap().keySet()) {
|
||||
if (transport.getId().equalsIgnoreCase(id))
|
||||
return transport;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Map of Transport and associated Modules for the current protocol.
|
||||
*/
|
||||
private Map<Transport, Collection<Module>> getTransportMap() {
|
||||
return logger.getProtocolList().get(settings.getLoggerProtocol());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Module based on its String name.
|
||||
*/
|
||||
private Module getModule(String name) {
|
||||
final Collection<Module> modules = getTransportMap().get(
|
||||
getTransportById(settings.getTransportProtocol()));
|
||||
for (Module module: modules) {
|
||||
if (module.getName().equalsIgnoreCase(name))
|
||||
return module;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load ECU def table names from a user customized properties file.
|
||||
* The file will replace the Class defined names if it is present.
|
||||
* Names in the file should be separated by the : character
|
||||
* @exception FileNotFoundException if the directory or file is not present
|
||||
* @exception IOException if there's some kind of IO error
|
||||
*/
|
||||
private void loadProperties() {
|
||||
final Properties learning = new Properties();
|
||||
FileInputStream propFile;
|
||||
try {
|
||||
propFile = new FileInputStream("./customize/ncslearning.properties");
|
||||
learning.load(propFile);
|
||||
final String ltft_table_column_names =
|
||||
learning.getProperty("ltft_table_column_names");
|
||||
String[] names = ltft_table_column_names.split(":", 0);
|
||||
LTFT_TABLE_COLUMN_NAMES = new ArrayList<String>();
|
||||
for (String name : names) {
|
||||
if (ParamChecker.isNullOrEmpty(name)) continue;
|
||||
LTFT_TABLE_COLUMN_NAMES.add(name);
|
||||
}
|
||||
final String ltft_table_row_names =
|
||||
learning.getProperty("ltft_table_row_names");
|
||||
names = ltft_table_row_names.split(":", 0);
|
||||
LTFT_TABLE_ROW_NAMES = new ArrayList<String>();
|
||||
for (String name : names) {
|
||||
if (ParamChecker.isNullOrEmpty(name)) continue;
|
||||
LTFT_TABLE_ROW_NAMES.add(name);
|
||||
}
|
||||
propFile.close();
|
||||
LOGGER.info("NCSLearningTableValues loaded table names from file: ./customize/ncslearning.properties");
|
||||
} catch (FileNotFoundException e) {
|
||||
LOGGER.error("NCSLearningTableValues properties file: " + e.getLocalizedMessage());
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("NCSLearningTableValues IOException: " + e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.logger.ecu.comms.learning.parameter;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This Emun defines all the possible parameters used to query the Learning
|
||||
* Table Values of an ECU.
|
||||
*/
|
||||
public enum NCSParameter {
|
||||
P2("P2"), // ECT
|
||||
P11("P11"), // IAT
|
||||
P17("P17"), // Battery Volts
|
||||
E173("E173"), // mixed ratio learning map trim
|
||||
E174("E174"); // mixed ratio learning map count
|
||||
|
||||
private static final Map<String, NCSParameter> lookup
|
||||
= new HashMap<String, NCSParameter>();
|
||||
|
||||
static {
|
||||
for(NCSParameter s : EnumSet.allOf(NCSParameter.class))
|
||||
lookup.put(s.toString(), s);
|
||||
}
|
||||
|
||||
private NCSParameter(final String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
private final String text;
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Parameter that has the given value.
|
||||
* @param value - the value of the Parameter in String format
|
||||
* @return the Parameter that has the given value or null if undefined.
|
||||
*/
|
||||
public static NCSParameter fromValue(String value) {
|
||||
NCSParameter result = null;
|
||||
if (lookup.containsKey(value)) {
|
||||
result = lookup.get(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.logger.ecu.comms.learning.parameter;
|
||||
|
||||
import static com.romraider.logger.ecu.comms.learning.parameter.NCSParameter.P11;
|
||||
import static com.romraider.logger.ecu.comms.learning.parameter.NCSParameter.P17;
|
||||
import static com.romraider.logger.ecu.comms.learning.parameter.NCSParameter.P2;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A Map of Parameter and value specific to the Vehicle Information Table.
|
||||
*/
|
||||
public class NCSParameterCrossReference {
|
||||
final Map<NCSParameter, String> map;
|
||||
|
||||
public NCSParameterCrossReference() {
|
||||
map = new HashMap<NCSParameter, String>();
|
||||
map.put(P17, "Battery");
|
||||
map.put(P11, "IAT");
|
||||
map.put(P2, "ECT");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the string value associated with the supplied Parameter.
|
||||
* @param parameter - Parameter to lookup value for.
|
||||
* @return the value of the Parameter.
|
||||
*/
|
||||
public final String getValue(NCSParameter parameter) {
|
||||
return map.get(parameter);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2015 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.logger.ecu.comms.learning.tableaxis;
|
||||
|
||||
import static com.romraider.logger.ecu.definition.xml.ConverterMaxMinDefaults.getDefault;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.romraider.Settings;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQuery;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQueryData;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQueryImpl;
|
||||
import com.romraider.logger.ecu.definition.EcuAddress;
|
||||
import com.romraider.logger.ecu.definition.EcuAddressImpl;
|
||||
import com.romraider.logger.ecu.definition.EcuData;
|
||||
import com.romraider.logger.ecu.definition.EcuDataConvertor;
|
||||
import com.romraider.logger.ecu.definition.EcuParameterConvertorImpl;
|
||||
import com.romraider.logger.ecu.definition.EcuParameterImpl;
|
||||
import com.romraider.util.HexUtil;
|
||||
|
||||
/**
|
||||
* Build a List of ECU Queries to retrieve a Table's axis values.
|
||||
*/
|
||||
public class NCSTableAxisQueryParameterSet {
|
||||
|
||||
private NCSTableAxisQueryParameterSet() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a List of ECU Queries.
|
||||
* @param storageAddress - the starting address of the Table.
|
||||
* @param storageType - the data storage type (big endian assumed).
|
||||
* @param expression - the equation to convert byte data to a real number.
|
||||
* @param units - the value's unit of measure.
|
||||
* @param size - the length of the Table's axis.
|
||||
* @param endian - the data endian.
|
||||
* @return a List of ECU Query items.
|
||||
*/
|
||||
public static final List<EcuQuery> build(
|
||||
String storageAddress,
|
||||
String storageType,
|
||||
String expression,
|
||||
String units,
|
||||
String size) {
|
||||
|
||||
final List<EcuQuery> tableAxisQuery = new ArrayList<EcuQuery>();
|
||||
final String tableAddrStr = storageAddress.replaceAll("0x", "");
|
||||
final int tableAddrBase = Integer.parseInt(tableAddrStr, 16);
|
||||
|
||||
int dataSize = EcuQueryData.getDataLength(storageType);
|
||||
|
||||
final int count = Integer.parseInt(size, 10);
|
||||
for (int i = 0; i < count; i++) {
|
||||
final String addrStr =
|
||||
HexUtil.intToHexString(tableAddrBase + (i * dataSize));
|
||||
final String id = addrStr + "-" + i;
|
||||
final EcuAddress ea = new EcuAddressImpl(addrStr, dataSize, -1);
|
||||
final EcuParameterImpl epi =
|
||||
new EcuParameterImpl(id, addrStr, id, ea, null, null, null,
|
||||
new EcuDataConvertor[] {
|
||||
new EcuParameterConvertorImpl(
|
||||
units, expression, "0.000", -1, storageType,
|
||||
Settings.ENDIAN_BIG, new HashMap<String, String>(),
|
||||
getDefault()
|
||||
)
|
||||
}
|
||||
);
|
||||
tableAxisQuery.add(new EcuQueryImpl((EcuData) epi));
|
||||
}
|
||||
return tableAxisQuery;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.logger.ecu.comms.learning.tables;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.romraider.logger.ecu.comms.query.EcuQuery;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQueryData;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQueryImpl;
|
||||
import com.romraider.logger.ecu.definition.EcuAddress;
|
||||
import com.romraider.logger.ecu.definition.EcuAddressImpl;
|
||||
import com.romraider.logger.ecu.definition.EcuData;
|
||||
import com.romraider.logger.ecu.definition.EcuDataConvertor;
|
||||
import com.romraider.logger.ecu.definition.EcuParameterImpl;
|
||||
import com.romraider.logger.ecu.ui.paramlist.ParameterRow;
|
||||
import com.romraider.util.HexUtil;
|
||||
|
||||
/**
|
||||
* Build an EcuQuery for each of the cells in the FLKC RAM table.
|
||||
*/
|
||||
public class NCSLtftTableQueryBuilder {
|
||||
private static final Logger LOGGER =
|
||||
Logger.getLogger(NCSLtftTableQueryBuilder.class);
|
||||
|
||||
public NCSLtftTableQueryBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an EcuQuery for each cell of the LTFT RAM table. <i>Note this
|
||||
* returns an extra null query for column 0 of each row which is later
|
||||
* populated with the row header (RPM Ranges) data.</i>
|
||||
* @param ltft - a ParameterRow item that helps to identify the
|
||||
* ECU bitness and provide a Converter for the raw data.
|
||||
* @param ltftAddr - the address in RAM of the start of the table.
|
||||
* @param rows - the number of rows in the table.
|
||||
* @param columns - the number of columns in the table.
|
||||
* @return EcuQueries divided into groups to query each row separately to
|
||||
* avoid maxing out the ECU send/receive buffer.
|
||||
*/
|
||||
public final List<List<EcuQuery>> build(
|
||||
ParameterRow ltft,
|
||||
int ltftAddr,
|
||||
int rows,
|
||||
int columns) {
|
||||
|
||||
final List<List<EcuQuery>> ltftQueryRows = new ArrayList<List<EcuQuery>>();
|
||||
final EcuData parameter = (EcuData) ltft.getLoggerData();
|
||||
int dataSize = EcuQueryData.getDataLength(parameter);
|
||||
LOGGER.debug(
|
||||
String.format(
|
||||
"LTFT Data format rows:%d col:%d " +
|
||||
"dataSize:%d LTFT:%s",
|
||||
rows, columns, dataSize,
|
||||
ltft.getLoggerData().getId()));
|
||||
|
||||
int i = 0;
|
||||
for (int j = 0; j < rows; j++) {
|
||||
final List<EcuQuery> ltftQueryCols = new ArrayList<EcuQuery>();
|
||||
ltftQueryCols.add(null);
|
||||
for (int k = 0; k < columns; k++) {
|
||||
String id = "flkc-r" + j + "c" + k;
|
||||
final String addrStr =
|
||||
HexUtil.intToHexString(
|
||||
ltftAddr + (i * dataSize));
|
||||
LOGGER.debug(
|
||||
String.format(
|
||||
"LTFT Data row:%d col:%d addr:%s",
|
||||
j, k, addrStr));
|
||||
final EcuAddress ea = new EcuAddressImpl(addrStr, dataSize, -1);
|
||||
final EcuParameterImpl epi =
|
||||
new EcuParameterImpl(id, addrStr, id, ea, null, null, null,
|
||||
new EcuDataConvertor[] {
|
||||
ltft.getLoggerData().getSelectedConvertor()
|
||||
}
|
||||
);
|
||||
ltftQueryCols.add(new EcuQueryImpl((EcuData) epi));
|
||||
i++;
|
||||
}
|
||||
ltftQueryRows.add(ltftQueryCols);
|
||||
}
|
||||
return ltftQueryRows;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.logger.ecu.comms.query;
|
||||
|
||||
import static com.romraider.util.ParamChecker.checkNotNullOrEmpty;
|
||||
import static java.lang.System.arraycopy;
|
||||
|
||||
public final class NCSEcuInit implements EcuInit {
|
||||
private byte[] ecuInitBytes;
|
||||
private String ecuId;
|
||||
|
||||
public NCSEcuInit(byte[] ecuInitBytes) {
|
||||
checkNotNullOrEmpty(ecuInitBytes, "ecuInitBytes");
|
||||
this.ecuInitBytes = ecuInitBytes;
|
||||
final byte[] ecuIdBytes = new byte[5];
|
||||
arraycopy(ecuInitBytes, 3, ecuIdBytes, 0, 5);
|
||||
ecuId = new String(ecuIdBytes);
|
||||
}
|
||||
|
||||
public String getEcuId() {
|
||||
return ecuId;
|
||||
}
|
||||
|
||||
public byte[] getEcuInitBytes() {
|
||||
return ecuInitBytes;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,409 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.logger.ecu.ui.swing.tools;
|
||||
|
||||
import static com.romraider.Settings.COMMA;
|
||||
import static javax.swing.JOptionPane.ERROR_MESSAGE;
|
||||
import static javax.swing.JOptionPane.INFORMATION_MESSAGE;
|
||||
import static javax.swing.JOptionPane.showMessageDialog;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.EtchedBorder;
|
||||
import javax.swing.border.TitledBorder;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import javax.swing.table.TableColumn;
|
||||
|
||||
import com.romraider.logger.ecu.EcuLogger;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQuery;
|
||||
import com.romraider.logger.ecu.ui.swing.tools.tablemodels.FineLearningKnockCorrectionTableModel;
|
||||
import com.romraider.logger.ecu.ui.swing.tools.tablemodels.VehicleInformationTableModel;
|
||||
import com.romraider.logger.ecu.ui.swing.tools.tablemodels.renderers.CentreRenderer;
|
||||
import com.romraider.logger.ecu.ui.swing.tools.tablemodels.renderers.LtvCellRenderer;
|
||||
import com.romraider.logger.ecu.ui.swing.vertical.VerticalLabelUI;
|
||||
import com.romraider.swing.SetFont;
|
||||
import com.romraider.util.FormatFilename;
|
||||
import com.romraider.util.SettingsManager;
|
||||
|
||||
/**
|
||||
* This class is used to build and display the Learning Table Values
|
||||
* retrieved from the ECU.
|
||||
*/
|
||||
public class NCSLearningTableValuesResultsPanel extends JDialog {
|
||||
private static final long serialVersionUID = 6716454297236022709L;
|
||||
private final String DIALOG_TITLE = "Learning Table Values";
|
||||
private final String DT_FORMAT = "%1$tY%1$tm%1$td-%1$tH%1$tM%1$tS";
|
||||
private final int LTV_WIDTH = 720;
|
||||
private final int LTV_HEIGHT = 450;
|
||||
private final JPanel contentPanel = new JPanel();
|
||||
private JTable vehicleInfoTable;
|
||||
//TODO: replace AF learning with a knock table
|
||||
private JTable afLearningTable;
|
||||
private List<JTable> ltftTables = new ArrayList<JTable>();
|
||||
private final String LTFT_NAME = "Long Term Fuel Trim Tables";
|
||||
|
||||
public NCSLearningTableValuesResultsPanel(
|
||||
EcuLogger logger,
|
||||
Map<String, Object> vehicleInfo,
|
||||
String[] afRanges,
|
||||
List<List<Object>> afLearning,
|
||||
String[] ltftCol,
|
||||
String[] ltftRow,
|
||||
List<List<List<EcuQuery>>> ltftData) {
|
||||
|
||||
super(logger, false);
|
||||
setIconImage(logger.getIconImage());
|
||||
setTitle(DIALOG_TITLE);
|
||||
setBounds(
|
||||
(logger.getWidth() > LTV_WIDTH) ?
|
||||
logger.getX() + (logger.getWidth() - LTV_WIDTH) / 2 : 0,
|
||||
(logger.getHeight() > LTV_HEIGHT) ?
|
||||
logger.getY() + ((logger.getHeight() - LTV_HEIGHT) / 2) : 0,
|
||||
LTV_WIDTH,
|
||||
LTV_HEIGHT);
|
||||
getContentPane().setLayout(new BorderLayout());
|
||||
|
||||
contentPanel.setBorder(new EmptyBorder(2, 2, 2, 2));
|
||||
contentPanel.setLayout(null);
|
||||
contentPanel.add(buildVehicleInfoPanel(vehicleInfo));
|
||||
// contentPanel.add(buildAfLearningPanel(afRanges, afLearning));
|
||||
contentPanel.add(buildLtftPanel(ltftCol, ltftRow, ltftData));
|
||||
|
||||
getContentPane().add(contentPanel, BorderLayout.CENTER);
|
||||
getContentPane().add(buildSaveReultsPanel(), BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to display the Learning Table Values
|
||||
* retrieved from the ECU.
|
||||
*/
|
||||
public final void displayLearningResultsPanel() {
|
||||
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
private final JPanel buildVehicleInfoPanel(
|
||||
Map<String, Object> vehicleInfo) {
|
||||
|
||||
final JPanel vehicleInfoTitlePanel = new JPanel();
|
||||
vehicleInfoTitlePanel.setBorder(
|
||||
BorderFactory.createTitledBorder("Vehicle Information"));
|
||||
vehicleInfoTitlePanel.setBounds(10, 2, 692, 70);
|
||||
vehicleInfoTitlePanel.setLayout(new BorderLayout(0, 0));
|
||||
|
||||
JPanel vehicleInfoTablePanel = new JPanel();
|
||||
vehicleInfoTablePanel.setBorder(
|
||||
new EtchedBorder(EtchedBorder.LOWERED, null, null));
|
||||
vehicleInfoTablePanel.setLayout(new BorderLayout(0, 0));
|
||||
|
||||
final VehicleInformationTableModel tableModel =
|
||||
new VehicleInformationTableModel();
|
||||
tableModel.setVehicleInfo(vehicleInfo);
|
||||
vehicleInfoTable = new JTable(tableModel);
|
||||
setTableBehaviour(vehicleInfoTable);
|
||||
|
||||
TableColumn column = null;
|
||||
for (int i = 0; i < vehicleInfoTable.getColumnCount(); i++) {
|
||||
column = vehicleInfoTable.getColumnModel().getColumn(i);
|
||||
if (i == 0 || i ==1) {
|
||||
column.setPreferredWidth(85);
|
||||
}
|
||||
else if (i == 2) {
|
||||
column.setPreferredWidth(200);
|
||||
}
|
||||
}
|
||||
|
||||
vehicleInfoTablePanel.add(
|
||||
formatTableHeader(vehicleInfoTable),
|
||||
BorderLayout.PAGE_START);
|
||||
vehicleInfoTablePanel.add(vehicleInfoTable);
|
||||
|
||||
vehicleInfoTitlePanel.add(vehicleInfoTablePanel, BorderLayout.CENTER);
|
||||
return vehicleInfoTitlePanel;
|
||||
}
|
||||
|
||||
private final JPanel buildLtftPanel(
|
||||
String[] ltftLoad,
|
||||
String[] ltftRpm,
|
||||
List<List<List<EcuQuery>>> ltftQueryTables) {
|
||||
|
||||
final JPanel ltftTitlePanel = new JPanel();
|
||||
ltftTitlePanel.setBorder(
|
||||
new TitledBorder(null,
|
||||
LTFT_NAME,
|
||||
TitledBorder.LEADING,
|
||||
TitledBorder.TOP, null, null));
|
||||
ltftTitlePanel.setBounds(10, 72, 692, 226);
|
||||
ltftTitlePanel.setLayout(new BorderLayout(0, 0));
|
||||
|
||||
final JLabel xLabel = new JLabel("Injector Pule Width (msec)");
|
||||
SetFont.plain(xLabel);
|
||||
xLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
ltftTitlePanel.add(xLabel, BorderLayout.NORTH);
|
||||
|
||||
final JLabel yLabel = new JLabel("Engine Speed (RPM)");
|
||||
SetFont.plain(yLabel);
|
||||
yLabel.setUI(new VerticalLabelUI(false));
|
||||
ltftTitlePanel.add(yLabel, BorderLayout.WEST);
|
||||
|
||||
final JTabbedPane tabs = new JTabbedPane();
|
||||
for (int i = 0; i < ltftQueryTables.size(); i++) {
|
||||
final FineLearningKnockCorrectionTableModel tableModel =
|
||||
new FineLearningKnockCorrectionTableModel();
|
||||
tableModel.setColumnHeadings(ltftLoad);
|
||||
tableModel.setRomHeadings(ltftRpm);
|
||||
tableModel.setFlkcData(ltftQueryTables.get(i));
|
||||
final JTable ltftTable = new JTable(tableModel);
|
||||
ltftTables.add(ltftTable);
|
||||
setTableBehaviour(ltftTable);
|
||||
formatTableHeader(ltftTable);
|
||||
final JScrollPane ltftTablePanel = new JScrollPane(ltftTable);
|
||||
ltftTablePanel.setBorder(
|
||||
new EtchedBorder(EtchedBorder.LOWERED, null, null));
|
||||
switch (i) {
|
||||
case 0:
|
||||
tabs.addTab("Left Bank - Trim (%)", ltftTablePanel);
|
||||
break;
|
||||
case 1:
|
||||
tabs.addTab("Right Bank - Trim (%)", ltftTablePanel);
|
||||
break;
|
||||
case 2:
|
||||
tabs.addTab("Left Bank - Count", ltftTablePanel);
|
||||
break;
|
||||
case 3:
|
||||
tabs.addTab("Right Bank - Count", ltftTablePanel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ltftQueryTables.size() > 0) {
|
||||
ltftTitlePanel.add(tabs, BorderLayout.CENTER);
|
||||
}
|
||||
else {
|
||||
ltftTitlePanel.removeAll();
|
||||
ltftTitlePanel.add(new JLabel(
|
||||
" No data - Knock Adaptation parameter ID not defined"),
|
||||
BorderLayout.CENTER);
|
||||
}
|
||||
return ltftTitlePanel;
|
||||
}
|
||||
|
||||
private final void setTableBehaviour(JTable table) {
|
||||
table.setBorder(null);
|
||||
table.setColumnSelectionAllowed(false);
|
||||
table.setRowSelectionAllowed(false);
|
||||
table.setFont(new Font("Tahoma", Font.PLAIN, 11));
|
||||
table.setFillsViewportHeight(true);
|
||||
table.setDefaultRenderer(Double.class, new LtvCellRenderer());
|
||||
table.setDefaultRenderer(String.class, new LtvCellRenderer());
|
||||
}
|
||||
|
||||
private final JTableHeader formatTableHeader(JTable table) {
|
||||
final JTableHeader th = table.getTableHeader();
|
||||
th.setReorderingAllowed(false);
|
||||
th.setDefaultRenderer(new CentreRenderer(table));
|
||||
SetFont.bold(th, 11);
|
||||
return th;
|
||||
}
|
||||
|
||||
private final JPanel buildSaveReultsPanel() {
|
||||
|
||||
final JPanel controlPanel = new JPanel();
|
||||
final JButton toFile = new JButton("Save to File");
|
||||
toFile.setToolTipText("Save tables to a text file");
|
||||
toFile.setMnemonic(KeyEvent.VK_F);
|
||||
toFile.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public final void actionPerformed(ActionEvent actionEvent) {
|
||||
saveTableText();
|
||||
}
|
||||
});
|
||||
final JButton toImage = new JButton("Save as Image");
|
||||
toImage.setToolTipText("Save tables as an image");
|
||||
toImage.setMnemonic(KeyEvent.VK_I);
|
||||
toImage.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public final void actionPerformed(ActionEvent actionEvent) {
|
||||
saveTableImage();
|
||||
}
|
||||
});
|
||||
controlPanel.add(toFile);
|
||||
controlPanel.add(toImage);
|
||||
return controlPanel;
|
||||
}
|
||||
|
||||
private final void saveTableText() {
|
||||
final String nowStr = String.format(DT_FORMAT, System.currentTimeMillis());
|
||||
final String fileName = String.format("%s%sromraiderLTV_%s.csv",
|
||||
SettingsManager.getSettings().getLoggerOutputDirPath(),
|
||||
File.separator,
|
||||
nowStr);
|
||||
try {
|
||||
final File csvFile = new File(fileName);
|
||||
final String EOL = System.getProperty("line.separator");
|
||||
final BufferedWriter bw = new BufferedWriter(
|
||||
new FileWriter(csvFile));
|
||||
bw.write("Learning Table Values" + EOL);
|
||||
Object result = 0;
|
||||
int columnCount = vehicleInfoTable.getColumnCount();
|
||||
for (int i = 0; i < columnCount; i++ ) {
|
||||
result = vehicleInfoTable.getTableHeader().getColumnModel().
|
||||
getColumn(i).getHeaderValue();
|
||||
bw.append(result.toString());
|
||||
bw.append(COMMA);
|
||||
}
|
||||
bw.append(EOL);
|
||||
for (int i = 0; i < columnCount; i++ ) {
|
||||
result = vehicleInfoTable.getValueAt(0, i);
|
||||
bw.append(result.toString());
|
||||
bw.append(COMMA);
|
||||
}
|
||||
bw.append(EOL + EOL);
|
||||
// bw.write("A/F Adaptation (Stored)" + EOL);
|
||||
// columnCount = afLearningTable.getColumnCount();
|
||||
// int rowCount = afLearningTable.getRowCount();
|
||||
// for (int i = 0; i < columnCount; i++) {
|
||||
// result = afLearningTable.getTableHeader().getColumnModel().
|
||||
// getColumn(i).getHeaderValue();
|
||||
// bw.append(result.toString());
|
||||
// bw.append(COMMA);
|
||||
// }
|
||||
// bw.append(EOL);
|
||||
// for (int i = 0; i < rowCount; i++) {
|
||||
// for (int j = 0; j < columnCount; j++) {
|
||||
// result = afLearningTable.getValueAt(i, j);
|
||||
// bw.append(result.toString());
|
||||
// bw.append(COMMA);
|
||||
// }
|
||||
// bw.append(EOL);
|
||||
// }
|
||||
bw.append(EOL);
|
||||
bw.write(LTFT_NAME + EOL);
|
||||
int k = 1;
|
||||
for (JTable ltftTable : ltftTables) {
|
||||
columnCount = ltftTable.getColumnCount();
|
||||
for (int i = 0; i < columnCount; i++) {
|
||||
result = ltftTable.getTableHeader().getColumnModel().
|
||||
getColumn(i).getHeaderValue();
|
||||
if (result.toString().equals(" ")) {
|
||||
switch (k) {
|
||||
case 1:
|
||||
result = "Left Bank - Trim (%)";
|
||||
break;
|
||||
case 2:
|
||||
result = "Right Bank - Trim (%)";
|
||||
break;
|
||||
case 3:
|
||||
result = "Left Bank - Count";
|
||||
break;
|
||||
case 4:
|
||||
result = "Right Bank - Count";
|
||||
break;
|
||||
}
|
||||
}
|
||||
bw.append(result.toString());
|
||||
bw.append(COMMA);
|
||||
}
|
||||
k++;
|
||||
}
|
||||
bw.append(EOL);
|
||||
int rowCount = ltftTables.get(0).getRowCount();
|
||||
for (int i = 0; i < rowCount; i++) {
|
||||
for (JTable ltftTable : ltftTables) {
|
||||
columnCount = ltftTable.getColumnCount();
|
||||
for (int j = 0; j < columnCount; j++) {
|
||||
result = ltftTable.getValueAt(i, j);
|
||||
bw.append(result.toString());
|
||||
bw.append(COMMA);
|
||||
}
|
||||
}
|
||||
bw.append(EOL);
|
||||
}
|
||||
bw.close();
|
||||
final String shortName = FormatFilename.getShortName(fileName);
|
||||
showMessageDialog(
|
||||
null,
|
||||
"Table's text saved to: " + shortName,
|
||||
"Save Success",
|
||||
INFORMATION_MESSAGE);
|
||||
}
|
||||
catch (Exception e) {
|
||||
showMessageDialog(
|
||||
null,
|
||||
"Failed to save tables, check path:\n" + fileName,
|
||||
"Save Failed",
|
||||
ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private final void saveTableImage() {
|
||||
final BufferedImage resultsImage = new BufferedImage(
|
||||
contentPanel.getWidth(),
|
||||
contentPanel.getHeight(),
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
contentPanel.paint(resultsImage.createGraphics());
|
||||
final String nowStr = String.format(DT_FORMAT, System.currentTimeMillis());
|
||||
final String fileName = String.format("%s%sromraiderLTV_%s.png",
|
||||
SettingsManager.getSettings().getLoggerOutputDirPath(),
|
||||
File.separator,
|
||||
nowStr);
|
||||
final String shortName = FormatFilename.getShortName(fileName);
|
||||
try {
|
||||
final File imageFile = new File(fileName);
|
||||
ImageIO.write(
|
||||
resultsImage,
|
||||
"png",
|
||||
imageFile);
|
||||
showMessageDialog(
|
||||
null,
|
||||
"Learning Table Values image saved to: " + shortName,
|
||||
"Save Success",
|
||||
INFORMATION_MESSAGE);
|
||||
}
|
||||
catch (Exception e) {
|
||||
showMessageDialog(
|
||||
null,
|
||||
"Failed to save image, check path:\n" + fileName,
|
||||
"Save Failed",
|
||||
ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue