Merge branch 'RomRaider:master' into ncs_conv

This commit is contained in:
Robin 2021-11-04 19:43:23 +01:00 committed by GitHub
commit be340e84d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 4373 additions and 1042 deletions

View File

@ -9,3 +9,4 @@ FASTK = {0} Fast-K:
CANBUS = {0} CAN bus:
EXTERNALS = Externals:
QUERYSTATS = {0}[ {1,number,0.00} queries/sec, {2,number,0.00} sec/query ]
STOPPING = Stopping ...

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2012 RomRaider.com
* Copyright (C) 2006-2021 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
@ -22,11 +22,43 @@ package com.romraider.io.connection;
import com.romraider.logger.ecu.comms.manager.PollingState;
public interface ConnectionManager {
/**
* Use the open method when communications to a Module requires a
* StartCommunication sequence, such as Five Baud or Fast Init.
* Include the StopCommunication sequence in the open so that
* if something fails, the stop sequence is pre-loaded for use.
* @param start - the byte sequence used to start comms
* @param stop - the byte sequence used to stop comss
*/
void open(byte[] start, byte[] stop);
/**
* Use this send method to send a request to a Module and return the
* Module's reply in response. Polling state can be slow or fast as
* provided by the PollingState parameter.
* @param request - the bytes to send to the Module
* @param response - a byte array sized to contain the Module's response
* @param pollState - polling state, State_0 (slow) or State_1 (fast)
*/
void send(byte[] request, byte[] response, PollingState pollState);
/**
* Use this send method to send bytes to a Module and return the
* Module's reply.
* @param bytes - the bytes to send to the Module
* @return A byte array of the Module's response, variable sized
*/
byte[] send(byte[] bytes);
/**
* Use this method to clear the communications line of any erroneous data.
* It can be called before closing off communications to clear buffers
* of stale data, or when changing polling modes.
*/
void clearLine();
/**
* Use this method to close communications with the Module.
*/
void close();
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2020 RomRaider.com
* Copyright (C) 2006-2021 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
@ -60,6 +60,10 @@ public final class ElmConnectionManager implements ConnectionManager {
// readTimeout = timeout;
}
@Override
public void open(byte[] start, byte[] stop) {
}
public int getCurrentProtocolMode() {
return elmMode;
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2018 RomRaider.com
* Copyright (C) 2006-2021 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
@ -46,16 +46,28 @@ public final class J2534ConnectionISO14230 implements ConnectionManager {
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};
private PollingState.State currentPollState;
private ConnectionProperties connectionProperties;
private String library;
private byte[] startRequest;
private byte[] stopRequest;
public J2534ConnectionISO14230(ConnectionProperties connectionProperties, String library) {
checkNotNull(connectionProperties, "connectionProperties");
checkNotNull(library, "library");
deviceId = -1;
commsStarted = false;
this.connectionProperties = connectionProperties;
timeout = (long)connectionProperties.getConnectTimeout();
this.library = library;
}
@Override
public void open(byte[] start, byte[] stop) {
checkNotNull(start, "start");
checkNotNull(stop, "stop");
startRequest = start;
stopRequest = stop;
initJ2534(connectionProperties, library);
LOGGER.info("J2534/ISO14230 connection initialised");
}
@ -65,7 +77,7 @@ public final class J2534ConnectionISO14230 implements ConnectionManager {
checkNotNull(request, "request");
checkNotNull(response, "response");
checkNotNull(pollState, "pollState");
if (pollState.getCurrentState() == PollingState.State.STATE_0 &&
pollState.getLastState() == PollingState.State.STATE_1) {
clearLine();
@ -90,6 +102,7 @@ public final class J2534ConnectionISO14230 implements ConnectionManager {
pollState.setNewQuery(true);
}
}
currentPollState = pollState.getCurrentState();
}
// Send request and wait specified time for response with unknown length
@ -101,13 +114,17 @@ public final class J2534ConnectionISO14230 implements ConnectionManager {
public void clearLine() {
boolean repeat = true;
if (currentPollState == PollingState.State.STATE_0) {
// Slow poll, no need to send break and clear the line
return;
}
while (repeat) {
LOGGER.debug("J2534/ISO14230 sending line break");
int p3_min = getP3Min();
setP3Min(2);
api.writeMsg(
channelId,
stopReq,
stopRequest,
0L,
TxFlags.WAIT_P3_MIN_ONLY);
setP3Min(p3_min);
@ -129,6 +146,7 @@ public final class J2534ConnectionISO14230 implements ConnectionManager {
} while (!empty && i <= 3);
}
try {
// if we are clearing the line due to a comms error, re-init to continue logging
fastInit();
}
catch (J2534Exception e) {
@ -172,7 +190,6 @@ public final class J2534ConnectionISO14230 implements ConnectionManager {
"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",
@ -250,14 +267,15 @@ public final class J2534ConnectionISO14230 implements ConnectionManager {
}
private void fastInit() {
final byte[] timing = api.fastInit(channelId, startReq);
final byte[] timing = api.fastInit(channelId, startRequest);
LOGGER.debug(String.format(
"J2534/ISO14230 Fast Init: deviceId:%d, channelId:%d, timing:%s",
deviceId, channelId, asHex(timing)));
commsStarted = true;
}
private void stopComms() {
final byte[] response = send(stopReq);
final byte[] response = send(stopRequest);
LOGGER.debug(String.format("Stop comms Response = %s", asHex(response)));
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2014 RomRaider.com
* Copyright (C) 2006-2021 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
@ -19,6 +19,7 @@
package com.romraider.io.j2534.api;
import static com.romraider.util.HexUtil.asHex;
import static com.romraider.util.ParamChecker.checkNotNull;
import static org.apache.log4j.Logger.getLogger;
@ -39,6 +40,7 @@ public final class J2534ConnectionISO15765 implements ConnectionManager {
private int deviceId;
private int msgId;
private final long timeout;
private byte[] stopRequest;
public J2534ConnectionISO15765(
ConnectionProperties connectionProperties,
@ -50,6 +52,19 @@ public final class J2534ConnectionISO15765 implements ConnectionManager {
LOGGER.info("J2534/ISO15765 connection initialized");
}
@Override
public void open(byte[] start, byte[] stop) {
checkNotNull(start, "start");
checkNotNull(start, "stop");
this.stopRequest = stop;
LOGGER.debug(String.format("Start Diagnostics Request ---> %s",
asHex(start)));
api.writeMsg(channelId, start, timeout, TxFlags.ISO15765_FRAME_PAD);
final byte[] response = api.readMsg(channelId, 1, timeout);
LOGGER.debug(String.format("Start Diagnostics Response <--- %s",
asHex(response)));
}
// Send request and wait for response with known length
@Override
public void send(byte[] request, byte[] response, PollingState pollState) {
@ -79,6 +94,12 @@ public final class J2534ConnectionISO15765 implements ConnectionManager {
@Override
public void close() {
LOGGER.debug(String.format("Stop Diagnostics Request ---> %s",
asHex(stopRequest)));
api.writeMsg(channelId, stopRequest, timeout, TxFlags.ISO15765_FRAME_PAD);
final byte[] response = api.readMsg(channelId, 1, timeout);
LOGGER.debug(String.format("Stop Diagnostics Response <--- %s",
asHex(response)));
stopFcFilter();
disconnectChannel();
closeDevice();

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2018 RomRaider.com
* Copyright (C) 2006-2021 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
@ -55,6 +55,10 @@ public final class J2534ConnectionISO9141 implements ConnectionManager {
LOGGER.info("J2534/ISO9141 connection initialised");
}
@Override
public void open(byte[] start, byte[] stop) {
}
// Send request and wait for response with known length
public void send(byte[] request, byte[] response, PollingState pollState) {
checkNotNull(request, "request");

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2018 RomRaider.com
* Copyright (C) 2006-2021 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
@ -22,6 +22,9 @@ package com.romraider.io.j2534.api;
import static com.romraider.util.HexUtil.asHex;
import static com.romraider.util.LogManager.initDebugLogging;
import java.util.ArrayList;
import java.util.List;
import com.romraider.io.j2534.api.J2534Impl.Config;
import com.romraider.io.j2534.api.J2534Impl.Flag;
import com.romraider.io.j2534.api.J2534Impl.Protocol;
@ -55,23 +58,76 @@ public class TestJ2534 {
int msgId = api.startPassMsgFilter(channelId, (byte) 0x00, (byte) 0x00);
try {
List<byte[]> msgs = new ArrayList<byte[]>();
byte[] ecuInit = null;
if (protocol.equalsIgnoreCase("ssm")) {
ecuInit = new byte[]{
(byte) 0x80, (byte) 0x10, (byte) 0xF0,
(byte) 0x01, (byte) 0xBF, (byte) 0x40};
msgs.add(ecuInit);
}
else if (protocol.equalsIgnoreCase("ds2")) {
ecuInit = new byte[]{
(byte) 0x12, (byte) 0x04, (byte) 0x00,
(byte) 0x16};
byte[] engine = new byte[]{
(byte) 0x12, (byte) 0x05, (byte) 0x0B,
(byte) 0x03, (byte) 0x1F};
byte[] swtch = new byte[]{
(byte) 0x12, (byte) 0x05, (byte) 0x0B,
(byte) 0x04, (byte) 0x18};
byte[] lambda = new byte[]{
(byte) 0x12, (byte) 0x05, (byte) 0x0B,
(byte) 0x91, (byte) 0x8D};
byte[] adapt = new byte[]{
(byte) 0x12, (byte) 0x05, (byte) 0x0B,
(byte) 0x92, (byte) 0x8E};
byte[] corr = new byte[]{
(byte) 0x12, (byte) 0x05, (byte) 0x0B,
(byte) 0x93, (byte) 0x8F};
byte[] cat = new byte[]{
(byte) 0x12, (byte) 0x05, (byte) 0x0B,
(byte) 0x94, (byte) 0x88};
byte[] status = new byte[]{
(byte) 0x12, (byte) 0x05, (byte) 0x0B,
(byte) 0x95, (byte) 0x89};
byte[] close = new byte[]{
(byte) 0x12, (byte) 0x05, (byte) 0x0B,
(byte) 0xFF, (byte) 0xE3};
byte[] _0C = new byte[]{
(byte) 0x12, (byte) 0x04, (byte) 0x0C,
(byte) 0x1A};
byte[] _0D = new byte[]{
(byte) 0x12, (byte) 0x04, (byte) 0x0D,
(byte) 0x1B};
byte[] _25 = new byte[]{
(byte) 0x12, (byte) 0x04, (byte) 0x25,
(byte) 0x33};
byte[] _53 = new byte[]{
(byte) 0x12, (byte) 0x04, (byte) 0x53,
(byte) 0x45};
msgs.add(ecuInit);
msgs.add(engine);
msgs.add(swtch);
msgs.add(lambda);
msgs.add(adapt);
msgs.add(corr);
msgs.add(cat);
msgs.add(status);
msgs.add(close);
msgs.add(_0C);
msgs.add(_0D);
msgs.add(_25);
msgs.add(_53);
}
api.writeMsg(channelId, ecuInit, 55L, TxFlags.NO_FLAGS);
System.out.println("Request = " + asHex(ecuInit));
for (byte[] msg : msgs) {
api.writeMsg(channelId, msg, 55L, TxFlags.NO_FLAGS);
System.out.println("Request = " + asHex(msg));
byte[] response = api.readMsg(channelId, 1, 2000L);
System.out.println("Response = " + asHex(response));
byte[] response = api.readMsg(channelId, 500L);
System.out.println("Response = " + asHex(response));
}
} finally {
api.stopMsgFilter(channelId, msgId);

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2020 RomRaider.com
* Copyright (C) 2006-2021 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
@ -19,6 +19,8 @@
package com.romraider.io.protocol;
import java.util.Map;
import com.romraider.logger.ecu.comms.manager.PollingState;
import com.romraider.logger.ecu.definition.Module;
@ -29,7 +31,7 @@ public interface ProtocolNCS extends Protocol {
byte[] constructReadSidPidRequest(Module module, byte sid, byte[][] pid);
byte[] constructLoadAddressRequest(byte[][] addresses);
byte[] constructLoadAddressRequest(Map<byte[], Integer> queryMap);
void validateLoadAddressResponse(byte[] response);
@ -39,4 +41,12 @@ public interface ProtocolNCS extends Protocol {
PollingState pollState);
byte[] constructEcuIdRequest(Module module);
byte[] constructEcuStopRequest(Module module);
byte[] constructStartDiagRequest(Module module);
byte[] constructElevatedDiagRequest(Module module);
byte[] constructReadMemoryRequest(Module module, byte[][] address, int numBytes);
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2020 RomRaider.com
* Copyright (C) 2006-2021 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
@ -28,6 +28,7 @@ import static java.lang.System.arraycopy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import com.romraider.io.protocol.Protocol;
@ -48,6 +49,21 @@ public final class NCSLoggerProtocol implements LoggerProtocolNCS {
return protocol.constructEcuFastInitRequest(module);
}
@Override
public byte[] constructStartDiagRequest(Module module) {
return protocol.constructStartDiagRequest(module);
}
@Override
public byte[] constructElevatedDiagRequest(Module module) {
return protocol.constructElevatedDiagRequest(module);
}
@Override
public byte[] constructEcuStopRequest(Module module) {
return protocol.constructEcuStopRequest(module);
}
@Override
public byte[] constructEcuInitRequest(Module module) {
return protocol.constructEcuInitRequest(module);
@ -91,6 +107,17 @@ public final class NCSLoggerProtocol implements LoggerProtocolNCS {
convertToByteAddresses(filteredQueries));
}
@Override
public byte[] constructReadMemoryRequest(Module module,
Collection<EcuQuery> queries, int length) {
return null;
}
@Override
public byte[] constructReadMemoryResponse(int requestSize, int length) {
return null;
}
@Override
public void validateLoadAddressResponse(byte[] response) {
protocol.validateLoadAddressResponse(response);
@ -170,6 +197,10 @@ public final class NCSLoggerProtocol implements LoggerProtocolNCS {
}
}
@Override
public void processReadMemoryResponses(Collection<EcuQuery> queries, byte[] response) {
}
@Override
public Protocol getProtocol() {
return protocol;
@ -189,7 +220,8 @@ public final class NCSLoggerProtocol implements LoggerProtocolNCS {
protocol.checkValidWriteResponse(data, response);
}
private Collection<EcuQuery> filterDuplicates(Collection<EcuQuery> queries) {
@Override
public Collection<EcuQuery> filterDuplicates(Collection<EcuQuery> queries) {
Collection<EcuQuery> filteredQueries = new ArrayList<EcuQuery>();
for (EcuQuery query : queries) {
if (!filteredQueries.contains(query)) {
@ -199,13 +231,8 @@ public final class NCSLoggerProtocol implements LoggerProtocolNCS {
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;
private Map<byte[], Integer> convertToByteAddresses(Collection<EcuQuery> queries) {
final Map<byte[], Integer> queryMap = new LinkedHashMap<byte[], Integer>();
for (EcuQuery query : queries) {
byte[] bytes = query.getBytes();
int addrCount = query.getAddresses().length;
@ -213,9 +240,9 @@ public final class NCSLoggerProtocol implements LoggerProtocolNCS {
for (int j = 0; j < addrCount; j++) {
final byte[] addr = new byte[addrLen];
arraycopy(bytes, j * addrLen, addr, 0, addr.length);
addresses[i++] = addr;
queryMap.put(addr, 1);
}
}
return addresses;
return queryMap;
}
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2020 RomRaider.com
* Copyright (C) 2006-2021 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
@ -26,6 +26,7 @@ import static com.romraider.util.ParamChecker.checkNotNullOrEmpty;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;
import com.romraider.io.connection.ConnectionProperties;
import com.romraider.io.connection.KwpConnectionProperties;
@ -53,6 +54,8 @@ public final class NCSProtocol implements ProtocolNCS {
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 STOP_COMMAND = (byte) 0x82;
public static final byte STOP_RESPONSE = (byte) 0xC2;
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;
@ -69,6 +72,7 @@ public final class NCSProtocol implements ProtocolNCS {
public static final int ADDRESS_SIZE = 3;
public static Module module;
@Override
public byte[] constructEcuFastInitRequest(Module module) {
checkNotNull(module, "module");
NCSProtocol.module = module;
@ -77,6 +81,27 @@ public final class NCSProtocol implements ProtocolNCS {
return request;
}
@Override
public byte[] constructEcuStopRequest(Module module) {
checkNotNull(module, "module");
NCSProtocol.module = module;
final byte[] request = buildRequest(
STOP_COMMAND, false, new byte[]{});
return request;
}
// not implemented
@Override
public byte[] constructStartDiagRequest(Module module) {
return null;
}
// not implemented
@Override
public byte[] constructElevatedDiagRequest(Module module) {
return null;
}
// not implemented
@Override
public byte[] constructEcuInitRequest(Module module) {
@ -133,12 +158,27 @@ public final class NCSProtocol implements ProtocolNCS {
}
@Override
public byte[] constructLoadAddressRequest(byte[][] addresses) {
checkNotNullOrEmpty(addresses, "addresses");
//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[0]));
}
@Override
public byte[] constructLoadAddressRequest(Map<byte[], Integer> queries) {
checkNotNullOrEmpty(queries, "queries");
// short header - false, length encoded into lower 5 bits of first byte
// 0x8Len 0x10 0xFC 0xac 0x81 fld_typ address1 [[fld_typ address2] ... [fld_typ addressN]] checksum
// short header - true
// Len 0xac 0x81 fld_typ address1 [[fld_typ address2] ... [fld_typ addressN]] checksum
byte [][] addresses = new byte[queries.size()][];
int i = 0;
for (byte [] query : queries.keySet()) {
addresses[i++] = query;
}
return buildLoadAddrRequest(true, addresses);
}
@ -201,6 +241,7 @@ public final class NCSProtocol implements ProtocolNCS {
@Override
//TODO: not yet implemented
// maybe use: Service $11 - Module reset
public byte[] constructEcuResetRequest(Module module, int resetCode) {
checkNotNull(module, "module");
NCSProtocol.module = module;
@ -375,7 +416,7 @@ public final class NCSProtocol implements ProtocolNCS {
if (tmp[0] == (byte) 0xFF) {
bb.write(FIELD_TYPE_83);
bb.write((byte) 0xFF);
bb.write(tmp);
bb.write(tmp, 0, 3);
}
else { //assume a short length ROM address
bb.write(FIELD_TYPE_83);

View File

@ -0,0 +1,305 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2021 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.iso15765;
import static com.romraider.io.protocol.ncs.iso15765.NCSProtocol.RESPONSE_NON_DATA_BYTES;
import static com.romraider.io.protocol.ncs.iso15765.NCSResponseProcessor.extractResponseData;
import static com.romraider.io.protocol.ncs.iso15765.NCSResponseProcessor.filterRequestFromResponse;
import static com.romraider.util.HexUtil.hexToInt;
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.LinkedHashMap;
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[] constructStartDiagRequest(Module module) {
return protocol.constructStartDiagRequest(module);
}
@Override
public byte[] constructElevatedDiagRequest(Module module) {
return protocol.constructElevatedDiagRequest(module);
}
@Override
public byte[] constructEcuInitRequest(Module module) {
return protocol.constructEcuInitRequest(module);
}
@Override
public byte[] constructEcuStopRequest(Module module) {
return protocol.constructEcuStopRequest(module);
}
@Override
public byte[] constructEcuIdRequest(Module module) {
return protocol.constructEcuIdRequest(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, convertToByteAddresses(queries));
}
@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);
// convert to address and data length
return protocol.constructLoadAddressRequest(
convertToByteAddressAndLen(filteredQueries));
}
@Override
public byte[] constructReadMemoryRequest(Module module,
Collection<EcuQuery> queries, int length) {
return protocol.constructReadMemoryRequest(
module, convertToByteAddresses(queries), length);
}
@Override
public byte[] constructReadMemoryResponse(int requestSize, int length) {
return new byte[RESPONSE_NON_DATA_BYTES + requestSize + length];
}
@Override
public void validateLoadAddressResponse(byte[] response) {
protocol.validateLoadAddressResponse(response);
}
@Override
public byte[] constructReadAddressResponse(
Collection<EcuQuery> queries, PollingState pollState) {
checkNotNullOrEmpty(queries, "queries");
int numBytes = 7;
if (pollState.isFastPoll()) {
numBytes = 6;
}
// CAN addr
// one byte - Response sid
// one byte - Response pid
// one byte - option
// variable bytes of data defined for pid
Collection<EcuQuery> filteredQueries = filterDuplicates(queries);
for (EcuQuery ecuQuery : filteredQueries) {
//numBytes += ecuQuery.getBytes().length;
numBytes += EcuQueryData.getDataLength(ecuQuery);
}
return new byte[(numBytes)];
}
@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 byte[] processEcuIdResponse(byte[] response) {
checkNotNullOrEmpty(response, "response");
return protocol.parseResponseData(response);
}
@Override
public byte[] processReadSidPidResponse(byte[] response) {
checkNotNullOrEmpty(response, "response");
return 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()));
}
}
/**
* Processes the response bytes and set individual response on corresponding
* query objects.
* The response data is based on the lowest EcuData address and the length
* is the result of the difference between the highest and lowest address.
* The index into the response array is based in the lowest address.
**/
public void processReadMemoryResponses(
Collection<EcuQuery> queries, byte[] response) {
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 lowestAddress = Integer.MAX_VALUE;
for (EcuQuery filteredQuery : filteredQueries) {
final int address = hexToInt(filteredQuery.getAddresses()[0]);
if (address < lowestAddress) {
lowestAddress = address;
}
}
int srcPos = 0;
for (EcuQuery filteredQuery : filteredQueries) {
int dataTypeLength = EcuQueryData.getDataLength(filteredQuery);
final byte[] bytes = new byte[dataTypeLength];
final int address = hexToInt(filteredQuery.getAddresses()[0]);
srcPos = address - lowestAddress;
arraycopy(responseData, srcPos, bytes, 0, bytes.length);
addressResults.put(filteredQuery.getHex(), bytes);
}
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);
}
@Override
public 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;
}
private Map<byte[], Integer> convertToByteAddressAndLen(Collection<EcuQuery> queries) {
final Map<byte[], Integer> queryMap = new LinkedHashMap<byte[], Integer>();
for (EcuQuery query : queries) {
queryMap.put(query.getBytes(), EcuQueryData.getDataLength(query));
}
return queryMap;
}
}

View File

@ -0,0 +1,377 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2021 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.iso15765;
import static com.romraider.util.HexUtil.asHex;
import static com.romraider.util.ParamChecker.checkGreaterThanZero;
import static com.romraider.util.ParamChecker.checkNotNull;
import static com.romraider.util.ParamChecker.checkNotNullOrEmpty;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;
import com.romraider.io.connection.ConnectionProperties;
import com.romraider.io.connection.KwpConnectionProperties;
import com.romraider.io.protocol.ProtocolNCS;
import com.romraider.io.protocol.ncs.iso15765.NCSResponseProcessor;
import com.romraider.io.protocol.ncs.iso15765.NCSProtocol;
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 READ_MEMORY_PADDING = (byte) 0x00;
public static final byte READ_MEMORY_COMMAND = (byte) 0x23;
public static final byte READ_MEMORY_RESPONSE = (byte) 0x63;
public static final byte LOAD_ADDRESS_COMMAND = (byte) 0x2C;
public static final byte DDLOCID = (byte) 0xE0;
public static final byte LOAD_ADDRESS_RESPONSE = (byte) 0x6C;
public static final byte READ_LOAD_COMMAND = (byte) 0x21;
public static final byte READ_LOAD_RESPONSE = (byte) 0x61;
public static final byte ECU_INIT_COMMAND = (byte) 0x10;
public static final byte ECU_INIT_RESPONSE = (byte) 0x50;
public static final byte ECU_ID_SID = (byte) 0x21;
public static final byte ECU_ID_CMD = (byte) 0x10;
public static final byte FIELD_TYPE_01 = (byte) 0x01;
public static final byte FIELD_TYPE_02 = (byte) 0x02;
public static final byte FIELD_TYPE_03 = (byte) 0x03;
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) 0x50;
public static final byte READ_SID_21_RESPONSE = (byte) 0x61;
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 = 4;
public static final int ADDRESS_SIZE = 4;
public static Module module;
// not implemented
@Override
public byte[] constructEcuFastInitRequest(Module module) {
return null;
}
@Override
public byte[] constructEcuStopRequest(Module module) {
checkNotNull(module, "module");
NCSProtocol.module = module;
// 000007E01081
final byte[] request = buildRequest(
ECU_INIT_COMMAND, false, new byte[]{(byte) 0x81});
return request;
}
@Override
public byte[] constructEcuInitRequest(Module module) {
checkNotNull(module, "module");
NCSProtocol.module = module;
// 000007E010C0
final byte[] request = buildRequest(
ECU_INIT_COMMAND, false, new byte[]{(byte) 0xC0});
return request;
}
@Override
public byte[] constructStartDiagRequest(Module module) {
checkNotNull(module, "module");
NCSProtocol.module = module;
// 000007E010C0
final byte[] request = buildRequest(
ECU_INIT_COMMAND, false, new byte[]{(byte) 0xC0});
return request;
}
@Override
public byte[] constructElevatedDiagRequest(Module module) {
checkNotNull(module, "module");
NCSProtocol.module = module;
// 000007E010FB
final byte[] request = buildRequest(
ECU_INIT_COMMAND, false, new byte[]{(byte) 0xFB});
return request;
}
@Override
public byte[] constructEcuIdRequest(Module module) {
checkNotNull(module, "module");
NCSProtocol.module = module;
// 000007E02110
final byte[] request = buildRequest(
ECU_ID_SID, false, new byte[]{ECU_ID_CMD});
return request;
}
@Override
public byte[] constructReadSidPidRequest(Module module, byte sid, byte[][] pid) {
checkNotNull(module, "module");
NCSProtocol.module = module;
final byte[] request = buildRequest(sid, false, 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
public byte[] constructWriteAddressRequest(
Module module, byte[] address, byte value) {
throw new UnsupportedProtocolException(
"Write Address command is not supported on for address: " +
asHex(address));
}
@Override
public byte[] constructReadMemoryRequest(Module module, byte[] address,
int numBytes) {
NCSProtocol.module = module;
// 000007E023 4-byte_address 2-byte_numBytes
final byte[] frame = new byte[6];
if (address[0] == -1) {
frame[0] = (byte) 0xFF;
}
System.arraycopy(address, 0, frame, 4-address.length, address.length);
frame[5] = (byte) numBytes;
return buildRequest(READ_MEMORY_COMMAND, false, frame, new byte[]{});
}
@Override
public byte[] constructReadMemoryRequest(
Module module, byte[][] address, int numBytes) {
checkNotNull(module, "module");
checkNotNullOrEmpty(address, "address");
checkGreaterThanZero(numBytes, "numBytes");
return constructReadMemoryRequest(module, address[0],
numBytes);
}
@Override
public byte[] constructLoadAddressRequest(Map<byte[], Integer> queryMap) {
checkNotNullOrEmpty(queryMap, "queryMap");
// ID 0x2C 0xE0 DEFMODE ... DEFMODE ... DEFMODE ...
return buildLoadAddrRequest(queryMap);
}
@Override
public byte[] constructReadAddressRequest(Module module, byte[][] addresses) {
// read addresses
// addr sid pid
return buildSidPidRequest(addresses);
}
@Override
public byte[] constructReadAddressRequest(Module module, byte[][] bs,
PollingState pollState) {
return buildRequest(
READ_LOAD_COMMAND, false, new byte[]{(byte) 0xE0});
}
@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
// maybe use: Service $11 with 0x80 - module reset
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 byte[] checkValidSidPidResponse(byte[] response) {
checkNotNullOrEmpty(response, "SidPidResponse");
return NCSResponseProcessor.extractResponseData(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 500000;
}
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 byte[] buildRequest(
byte command,
boolean padContent,
byte[]... content) {
bb.reset();
try {
bb.write(module.getTester());
bb.write(command);
if (padContent) {
bb.write(READ_MEMORY_PADDING);
}
for (byte[] tmp : content) {
bb.write(tmp);
}
} catch (IOException e) {
e.printStackTrace();
}
return bb.toByteArray();
}
private final byte[] buildSidPidRequest(byte[]... content) {
bb.reset();
try {
bb.write(module.getTester());
for (byte[] tmp : content) {
bb.write(tmp);
}
} catch (IOException e) {
e.printStackTrace();
}
return bb.toByteArray();
}
private final byte[] buildLoadAddrRequest(Map<byte[], Integer> queryMap) {
int PIDYDLID = 1;
byte[] request = new byte[0];
try {
bb.reset();
bb.write(module.getTester());
bb.write(LOAD_ADDRESS_COMMAND);
bb.write(DDLOCID);
for (byte[] tmp : queryMap.keySet()) {
if (tmp[0] == SID_22) {
bb.write(FIELD_TYPE_02); //definitionMode
bb.write(PIDYDLID++); //positionIn
bb.write(queryMap.get(tmp)); //size
bb.write(tmp, 1, tmp.length - 1);//CID
bb.write(1); //positionInRecord
continue;
}
else if (tmp[0] == (byte) 0xFF) {
bb.write(FIELD_TYPE_03); //definitionMode
bb.write(PIDYDLID++); //positionIn
bb.write(queryMap.get(tmp));//size (could be 1, 2 or 4)
bb.write((byte) 0xFF); //RAM addr high byte
bb.write(tmp, 0, 3); //RAM addr
}
}
request = bb.toByteArray();
}
catch (IOException e) {
e.printStackTrace();
}
return request;
}
}

View File

@ -0,0 +1,159 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2021 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.iso15765;
import static com.romraider.io.protocol.ncs.iso15765.NCSProtocol.module;
import static com.romraider.io.protocol.ncs.iso15765.NCSProtocol.ECU_INIT_RESPONSE;
import static com.romraider.io.protocol.ncs.iso15765.NCSProtocol.ECU_ID_SID_RESPONSE;
import static com.romraider.io.protocol.ncs.iso15765.NCSProtocol.READ_SID_21_RESPONSE;
import static com.romraider.io.protocol.ncs.iso15765.NCSProtocol.NCS_NRC;
import static com.romraider.io.protocol.ncs.iso15765.NCSProtocol.READ_SID_GRP_RESPONSE;
import static com.romraider.io.protocol.ncs.iso15765.NCSProtocol.READ_MEMORY_RESPONSE;
import static com.romraider.io.protocol.ncs.iso15765.NCSProtocol.RESPONSE_NON_DATA_BYTES;
import static com.romraider.io.protocol.ncs.iso15765.NCSProtocol.LOAD_ADDRESS_RESPONSE;
import static com.romraider.io.protocol.ncs.iso15765.NCSProtocol.READ_LOAD_RESPONSE;
import static com.romraider.util.ByteUtil.asUnsignedInt;
import static com.romraider.util.HexUtil.asHex;
import static com.romraider.util.ParamChecker.checkNotNullOrEmpty;
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 static void validateResponse(byte[] response) {
assertTrue(response.length > RESPONSE_NON_DATA_BYTES, "Invalid response length");
assertEquals(module.getAddress(), response, "Invalid " +
module.getName() + " id");
if (response[4] == NCS_NRC) {
assertNrc(NCS_NRC, response[4], response[5], response[6], "Request type not supported");
}
assertOneOf(new byte[]{ECU_INIT_RESPONSE, ECU_ID_SID_RESPONSE,
READ_SID_21_RESPONSE, READ_SID_GRP_RESPONSE,
READ_MEMORY_RESPONSE, LOAD_ADDRESS_RESPONSE,
READ_LOAD_RESPONSE}, response[4], "Invalid response code");
}
public static byte[] extractResponseData(byte[] response) {
checkNotNullOrEmpty(response, "response");
// 0x00 0x00 0x07 0xe0 response_command response_data
validateResponse(response);
int nonDataLength = 0;
byte[] data = new byte[]{};
if (response[4] == ECU_ID_SID_RESPONSE) {
nonDataLength = RESPONSE_NON_DATA_BYTES;
}
else if (response[4] == READ_SID_21_RESPONSE) {
nonDataLength = RESPONSE_NON_DATA_BYTES + 2;
}
else if (response[4] == READ_SID_GRP_RESPONSE) {
nonDataLength = RESPONSE_NON_DATA_BYTES + 3;
}
else if (response[4] == READ_MEMORY_RESPONSE) {
nonDataLength = RESPONSE_NON_DATA_BYTES + 1;
}
else if (response[4] == LOAD_ADDRESS_RESPONSE) {
nonDataLength = RESPONSE_NON_DATA_BYTES + 2;
}
else if (response[4] == READ_LOAD_RESPONSE) {
nonDataLength = RESPONSE_NON_DATA_BYTES + 2;
}
data = new byte[response.length - nonDataLength];
System.arraycopy(response, nonDataLength, data, 0, data.length);
return data;
}
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 == 0x11) {
ec = "mode not supported.";
}
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 static void assertEquals(byte[] expected, byte[] actual, String msg) {
final byte[] idBytes = new byte[4];
System.arraycopy(actual, 0, idBytes, 0, 4);
final int idExpected = asUnsignedInt(expected);
final int idActual = asUnsignedInt(idBytes);
if (idActual != idExpected) {
throw new InvalidResponseException(msg + ". Expected: " + asHex(expected) + ". Actual: " + asHex(idBytes) + ".");
}
}
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)));
}
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2016 RomRaider.com
* Copyright (C) 2006-2021 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
@ -53,6 +53,10 @@ public final class SerialConnectionManager implements ConnectionManager {
//connection = new TestSerialConnection2(portName, connectionProperties);
}
@Override
public void open(byte[] start, byte[] stop) {
}
// Send request and wait for response with known length
@Override
public void send(byte[] request, byte[] response, PollingState pollState) {

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2020 RomRaider.com
* Copyright (C) 2006-2021 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
@ -64,6 +64,10 @@ public final class DS2LoggerConnection implements LoggerConnection {
settings.getTransportProtocol());
}
@Override
public void open(Module module) {
}
@Override
public void ecuReset(Module module, int resetCode) {
byte[] request = protocol.constructEcuResetRequest(module, resetCode);
@ -121,7 +125,7 @@ public final class DS2LoggerConnection implements LoggerConnection {
}
// read data starting at address [00 SG HI LO NN] NN - number of bytes<249
else if (groupTest.startsWith("0x060x00")) {
final EcuQueryRangeTest range = new EcuQueryRangeTest(querySet);
final EcuQueryRangeTest range = new EcuQueryRangeTest(querySet, 128);
final Collection<EcuQuery> newQuery = range.validate();
int length = range.getLength();
if (newQuery != null && length > 0) {
@ -162,7 +166,9 @@ public final class DS2LoggerConnection implements LoggerConnection {
|| groupTest.startsWith("0x0b0x04")
|| groupTest.startsWith("0x0b0x91")
|| groupTest.startsWith("0x0b0x92")
|| groupTest.startsWith("0x0b0x93")) {
|| groupTest.startsWith("0x0b0x93")
|| groupTest.startsWith("0x0b0x94")
|| groupTest.startsWith("0x0b0x95")) {
request = protocol.constructReadGroupRequest(
module, group);

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2020 RomRaider.com
* Copyright (C) 2006-2021 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
@ -54,7 +54,11 @@ public final class ELMOBDLoggerConnection implements LoggerConnection {
}
@Override
//ToDo
public void open(Module module) {
}
@Override
// TODO:
public void ecuReset(Module module, int resetCode) {
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2015 RomRaider.com
* Copyright (C) 2006-2021 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
@ -28,15 +28,52 @@ import java.util.Collection;
import java.util.Map;
public interface LoggerConnection {
/**
* Use the open method when communications to a Module requires a
* StartCommunication sequence, such as Five Baud or Fast Init.
* @param module - the Module to open
*/
void open(Module module);
/**
* Use this method to reset the module.
* @param module - the Module to reset
* @param resetCode - the reset procedure to activate
*/
void ecuReset(Module module, int resetCode);
/**
* Use this method to get the identity the Module communicating with.
* @param callback - callback which will identify the Module
* @param module - the Module to identify
*/
void ecuInit(EcuInitCallback callback, Module module);
/**
* Use this method to query the Module for the parameters included as queries.
* @param queries - the Collection of EcuQuery items
* @param module - the Module to query
* @param pollState - the PollingState to use
*/
void sendAddressReads(Collection<EcuQuery> queries, Module module, PollingState pollState);
/**
* Use this method to clear the communications line of any erroneous data.
* It can be called before closing off communications to clear buffers
* of stale data, or when changing polling modes.
*/
void clearLine();
/**
* Use this method to close communications with the Module.
*/
void close();
/**
* Use this method to write to a Module.
* @param writeQueries - a Map of EcuQuery items to write
* @param module - the Module to write to
*/
void sendAddressWrites(Map<EcuQuery, byte[]> writeQueries, Module module);
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2020 RomRaider.com
* Copyright (C) 2006-2021 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
@ -24,6 +24,7 @@ import static com.romraider.util.ParamChecker.checkNotNull;
import static com.romraider.util.ThreadUtil.sleep;
import static org.apache.log4j.Logger.getLogger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.ResourceBundle;
@ -40,6 +41,8 @@ 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.comms.query.EcuQueryData;
import com.romraider.logger.ecu.comms.query.EcuQueryRangeTest;
import com.romraider.logger.ecu.definition.Module;
import com.romraider.logger.ecu.exception.SerialCommunicationException;
@ -50,14 +53,21 @@ public final class NCSLoggerConnection implements LoggerConnection {
private final LoggerProtocolNCS protocol;
private final ConnectionManager manager;
private int queryCount;
private final Settings settings = SettingsManager.getSettings();
private final Collection<EcuQuery> scQuery = new ArrayList<EcuQuery>();
private final Collection<EcuQuery> ramQuery = new ArrayList<EcuQuery>();
private boolean commsStarted;
private boolean elevatedDiag;
public NCSLoggerConnection(ConnectionManager manager) {
checkNotNull(manager, "manager");
this.manager = manager;
final Settings settings = SettingsManager.getSettings();
this.protocol = (LoggerProtocolNCS) ProtocolFactory.getProtocol(
settings.getLoggerProtocol(),
settings.getTransportProtocol());
commsStarted = false;
elevatedDiag = false;
}
@Override
@ -76,13 +86,17 @@ public final class NCSLoggerConnection implements LoggerConnection {
@Override
// Build an init string similar to the SSM version so the logger definition
// can reference supported parameters with ecubyte/bit attributes.
// can reference supported parameters using ecubyte/bit attributes.
public void ecuInit(EcuInitCallback callback, Module module) {
// ConnectionManger must have completed a fastInit to start comms
if (!commsStarted) open(module);
final byte[] initResponse = new byte[422];
byte[] request = protocol.constructEcuIdRequest(module);
byte[] request;
byte[] response;
request = protocol.constructEcuIdRequest(module);
LOGGER.debug(String.format("%s ID Request ---> %s",
module, asHex(request)));
byte[] response = manager.send(request);
response = manager.send(request);
LOGGER.debug(String.format("%s ID Raw Response <--- %s",
module, asHex(response)));
response = protocol.processEcuIdResponse(response);
@ -120,7 +134,7 @@ public final class NCSLoggerConnection implements LoggerConnection {
}
sid = (byte) 0x22;
final byte[] highBytes = {
(byte) 0x11, (byte) 0x12, (byte) 0x13, (byte) 0x14,
(byte) 0x11, (byte) 0x12, (byte) 0x13,
(byte) 0x15};
for (byte hb : highBytes) {
if (hb == (byte) 0x13) { // Supported Switch PIDs
@ -211,48 +225,21 @@ public final class NCSLoggerConnection implements LoggerConnection {
Module module,
PollingState pollState) {
if (queries.size() != queryCount
|| pollState.isNewQuery()) {
// max data bytes 63 when length encoded into format byte
int dataLength = 0;
for (EcuQuery query : queries) {
for (final String address : query.getAddresses()) {
dataLength += calcLength(address);
}
}
// if length is too big then notify user to un-select some parameters
if (dataLength > 61) {
throw new SerialCommunicationException(
rb.getString("TOOLARGE"));
}
final byte[] request = protocol.constructLoadAddressRequest(queries);
LOGGER.debug(String.format("Mode:%s %s Load address request ---> %s",
pollState.getCurrentState(), module, asHex(request)));
// ConnectionManger must have completed a fastInit to start comms
if (!commsStarted) open(module);
byte[] response = new byte[4]; // short header response
if ((request[0] & (byte)0x80) == (byte)0x80) {
response = new byte[6]; // long header response
}
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();
// CAN Slow poll, read each parameter in a separate query, inefficient
if (settings.isCanBus() && !pollState.isFastPoll()) {
doSlowCanQueries(queries, module, pollState);
}
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);
// Use CAN UDS 2C to load parameters and then request to read all loaded
else if (settings.isCanBus() && pollState.isFastPoll()) {
doFastCanQueries(queries, module, pollState);
}
// if not CAN do k-line queries
else {
doKlineQueries(queries, module, pollState);
}
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() {
@ -265,8 +252,23 @@ public final class NCSLoggerConnection implements LoggerConnection {
manager.clearLine();
}
@Override
public void open(Module module) {
// For k-line, get the fast init sequence and stop command, then open
// the connection via the ConnectionManager
byte[] start = protocol.constructEcuFastInitRequest(module);
byte[] stop = protocol.constructEcuStopRequest(module);
// For CAN, start a standard diagnostics session
if (settings.isCanBus()) {
start = protocol.constructStartDiagRequest(module);
}
manager.open(start, stop);
commsStarted = true;
}
@Override
public void close() {
commsStarted = false;
clearQueryCount();
manager.close();
}
@ -284,4 +286,243 @@ public final class NCSLoggerConnection implements LoggerConnection {
return 5;
}
}
private void doKlineQueries(
Collection<EcuQuery> queries,
Module module,
PollingState pollState) {
// k-line max data bytes is 63 when length encoded into format byte
if (queries.size() != queryCount
|| pollState.isNewQuery()) {
int dataLength = 0;
for (EcuQuery query : queries) {
for (final String address : query.getAddresses()) {
dataLength += calcLength(address);
}
}
// if length is too big then notify user to un-select some parameters
if (dataLength > 61) {
throw new SerialCommunicationException(
rb.getString("TOOLARGE"));
}
}
if (queries.size() != queryCount
|| pollState.isNewQuery()) {
final byte[] request = protocol.constructLoadAddressRequest(queries);
LOGGER.debug(String.format("Mode:%s %s Load address request ---> %s",
pollState.getCurrentState(), module, asHex(request)));
byte[] response = new byte[4]; // short header response
if ((request[0] & (byte)0x80) == (byte)0x80) {
response = new byte[6]; // long header response
}
protocol.validateLoadAddressResponse(
sendRcv(module, request, response, pollState));
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);
protocol.processReadAddressResponses(
queries,
sendRcv(module, request, response, pollState),
pollState);
}
/**
* SID/CID can't be combined with reading memory addresses direct,
* so we need to load and read each group separately.
* The queries are divided into and added to the class attributes scQuery
* and ramQuery collections.
* @param queries - the collection of queries to evaluate and split
*/
private void splitSidFromRamQueries(Collection<EcuQuery> queries) {
scQuery.clear();
ramQuery.clear();
for (EcuQuery query : queries) {
final String[] addresses = query.getAddresses();
for (final String address : addresses) {
if (address.startsWith("0x22")) { // SID&CID
scQuery.add(query);
break;
}
else {
ramQuery.add(query);
break;
}
}
}
}
private void doSlowCanQueries(
Collection<EcuQuery> queries,
Module module,
PollingState pollState) {
splitSidFromRamQueries(queries);
byte[] request;
byte[] response;
if (!scQuery.isEmpty()) {
final Collection<EcuQuery> sidQuery = new ArrayList<EcuQuery>();
for (EcuQuery query : scQuery) {
// for each query in the collection create a new collection with one item
sidQuery.clear();
sidQuery.add(query);
if (elevatedDiag) {
request = protocol.constructStartDiagRequest(module);
LOGGER.debug(String.format("%s Standard Diagnostics Request ---> %s",
module, asHex(request)));
response = manager.send(request);
LOGGER.debug(String.format("%s Standard Diagnostics Response <--- %s",
module, asHex(response)));
elevatedDiag = false;
}
request = protocol.constructReadAddressRequest(
module, sidQuery);
response = new byte[0];
LOGGER.debug(module + " CAN Request ---> " + asHex(request));
response = protocol.constructReadAddressResponse(
sidQuery, pollState);
protocol.processReadAddressResponses(
sidQuery,
sendRcv(module, request, response, pollState),
pollState);
}
}
// if query address is not an SID, elevate diag session and
// switch to SID 23 using readMemoryRequest
if (!ramQuery.isEmpty()) {
if (!elevatedDiag) {
request = protocol.constructElevatedDiagRequest(module);
LOGGER.debug(String.format("%s Elevated Diagnostics Request ---> %s",
module, asHex(request)));
response = manager.send(request);
LOGGER.debug(String.format("%s Elevated Diagnostics Response <--- %s",
module, asHex(response)));
elevatedDiag = true;
}
// Inspect the address of each query to determine if a single query
// with a start address and byte length can be substituted as opposed
// to querying each address separately.
final EcuQueryRangeTest range = new EcuQueryRangeTest(ramQuery, 63);
final Collection<EcuQuery> newQuery = range.validate();
int length = range.getLength();
if (newQuery != null && length > 0) {
request = protocol.constructReadMemoryRequest(module, newQuery, length);
LOGGER.debug(module + " CAN $23 Request ---> " + asHex(request));
response = protocol.constructReadMemoryResponse(1, length);
protocol.processReadMemoryResponses(
ramQuery,
sendRcv(module, request, response, pollState));
}
else {
// for each query in the collection create a new collection with one item
for (EcuQuery query : ramQuery) {
newQuery.clear();
newQuery.add(query);
request = protocol.constructReadMemoryRequest(
module, newQuery, EcuQueryData.getDataLength(query));
LOGGER.debug(String.format("Mode:%s %s Memory request ---> %s",
pollState.getCurrentState(), module, asHex(request)));
response = protocol.constructReadMemoryResponse(1,
EcuQueryData.getDataLength(query));
protocol.processReadMemoryResponses(
newQuery,
sendRcv(module, request, response, pollState));
}
}
}
}
private void doFastCanQueries (
Collection<EcuQuery> queries,
Module module,
PollingState pollState) {
// When parameter selection changes or there are RAM parameters present
// load and read the SID/CID parameters separate from the RAM parameters
if (queries.size() != queryCount
|| pollState.isNewQuery()) {
splitSidFromRamQueries(queries);
queryCount = queries.size();
pollState.setNewQuery(true);
}
byte[] request;
byte[] response;
if (!scQuery.isEmpty()) { // SID/CID queries
if (pollState.isNewQuery() || !ramQuery.isEmpty()) {
request = protocol.constructLoadAddressRequest(scQuery);
LOGGER.debug(String.format("Mode:%s %s Load address request ---> %s",
pollState.getCurrentState(), module, asHex(request)));
// CAN max is 99 bytes
if (request.length > 99) {
throw new SerialCommunicationException(
rb.getString("TOOLARGE"));
}
response = manager.send(request);
LOGGER.debug(String.format("Mode:%s %s Load address response <--- %s",
pollState.getCurrentState(), module, asHex(response)));
protocol.validateLoadAddressResponse(response);
}
request = protocol.constructReadAddressRequest(
module, scQuery, pollState);
response = protocol.constructReadAddressResponse(
scQuery, pollState);
protocol.processReadAddressResponses(
scQuery,
sendRcv(module, request, response, pollState),
pollState);
}
// When parameter selection changes or there are SID CID parameters present
// load and read the RAM parameters separate from the SID CID parameters
if (!ramQuery.isEmpty()) { // RAM queries
if (pollState.isNewQuery() || !scQuery.isEmpty()) {
request = protocol.constructLoadAddressRequest(ramQuery);
LOGGER.debug(String.format("Mode:%s %s Load address request ---> %s",
pollState.getCurrentState(), module, asHex(request)));
// CAN max is 99 bytes
if (request.length > 99) {
throw new SerialCommunicationException(
rb.getString("TOOLARGE"));
}
response = manager.send(request);
LOGGER.debug(String.format("Mode:%s %s Load address response <--- %s",
pollState.getCurrentState(), module, asHex(response)));
protocol.validateLoadAddressResponse(response);
pollState.setFastPoll(true);
}
request = protocol.constructReadAddressRequest(
module, ramQuery, pollState);
response = protocol.constructReadAddressResponse(
ramQuery, pollState);
protocol.processReadAddressResponses(
ramQuery,
sendRcv(module, request, response, pollState),
pollState);
}
}
private byte[] sendRcv(
Module module, byte[] request,
byte[] response, PollingState pollState) {
manager.send(request, response, pollState);
LOGGER.trace(module + " Read Raw Response <--- " + asHex(response));
final byte[] processedResponse = protocol.preprocessResponse(
request, response, pollState);
LOGGER.debug("Mode:" + pollState.getCurrentState() + " " +
module + " Response <--- " + asHex(processedResponse));
return processedResponse;
}
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2020 RomRaider.com
* Copyright (C) 2006-2021 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
@ -53,6 +53,10 @@ public final class OBDLoggerConnection implements LoggerConnection {
this.protocol = (LoggerProtocolOBD) ProtocolFactory.getProtocol(settings.getLoggerProtocol(), settings.getTransportProtocol());
}
@Override
public void open(Module module) {
}
@Override
public void ecuReset(Module module, int resetCode) {
byte[] request = protocol.constructEcuResetRequest(module, resetCode);

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2015 RomRaider.com
* Copyright (C) 2006-2021 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
@ -58,6 +58,10 @@ public final class SSMLoggerConnection implements LoggerConnection {
settings.getTransportProtocol());
}
@Override
public void open(Module module) {
}
@Override
public void ecuReset(Module module, int resetCode) {
byte[] request = protocol.constructEcuResetRequest(module, resetCode);

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2020 RomRaider.com
* Copyright (C) 2006-2021 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
@ -44,4 +44,18 @@ public interface LoggerProtocolNCS extends LoggerProtocol {
byte[] constructEcuIdRequest(Module module);
byte[] processEcuIdResponse(byte[] response);
byte[] constructEcuStopRequest(Module module);
byte[] constructStartDiagRequest(Module module);
byte[] constructElevatedDiagRequest(Module module);
Collection<EcuQuery> filterDuplicates(Collection<EcuQuery> queries);
byte[] constructReadMemoryRequest(Module module, Collection<EcuQuery> queries, int length);
byte[] constructReadMemoryResponse(int requestSize, int length);
void processReadMemoryResponses(Collection<EcuQuery> queries, byte[] response);
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2019 RomRaider.com
* Copyright (C) 2006-2021 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
@ -149,12 +149,17 @@ public final class DS2LearningTableValues extends SwingWorker<Void, Void>
try {
Collection<EcuQuery> queries = buildLearningQueries();
LOGGER.info("Retrieving vehicle info & A/F values ...");
connection.sendAddressReads(
queries,
settings.getDestinationTarget(),
new PollingStateImpl());
LOGGER.info("Current vehicle info & A/F values retrieved.");
try {
LOGGER.info("Retrieving vehicle info & A/F values ...");
connection.sendAddressReads(
queries,
settings.getDestinationTarget(),
new PollingStateImpl());
LOGGER.info("Current vehicle info & A/F values retrieved.");
}
catch (Exception e) {
LOGGER.error(message + " Error retrieving values", e);
}
Collections.sort(
(List<EcuQuery>)queries, new ParameterIdComparator());

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2019 RomRaider.com
* Copyright (C) 2006-2021 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
@ -57,8 +57,6 @@ 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;
@ -140,13 +138,6 @@ public final class NCSLearningTableValues extends SwingWorker<Void, Void>
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();
@ -361,8 +352,8 @@ public final class NCSLearningTableValues extends SwingWorker<Void, Void>
}
finally {
connection.close();
settings.setTransportProtocol(transport);
settings.setDestinationTarget(module);
// settings.setTransportProtocol(transport);
// settings.setDestinationTarget(module);
if (logging) logger.startLogging();
}
}
@ -549,37 +540,6 @@ public final class NCSLearningTableValues extends SwingWorker<Void, Void>
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.

View File

@ -330,7 +330,9 @@ public final class QueryManagerImpl implements QueryManager {
}
} catch (Exception e) {
messageListener.reportError(e);
sleep(500L);
} finally {
messageListener.reportMessage(rb.getString("STOPPING"));
txManager.stop();
pollState.setCurrentState(PollingState.State.STATE_0);
pollState.setNewQuery(true);

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2012 RomRaider.com
* Copyright (C) 2006-2021 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
@ -21,11 +21,28 @@ package com.romraider.logger.ecu.comms.query;
public interface EcuQuery extends Query {
/**
* Return a list of Strings, each entry in the list is an address of this
* query. For byte data there's only one address in the list, for word
* data there are two addresses in the list, for Dword there are four
* addresses in the list.
*/
String[] getAddresses();
/**
* Return a byte array made up from all of the addresses for this query.
*/
byte[] getBytes();
/**
* Return a String made up from all of the addresses for this query in hex
* format.
*/
String getHex();
/**
* Set the byte array that represents the response data for the query.
* @param bytes
*/
void setResponse(byte[] bytes);
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2015 RomRaider.com
* Copyright (C) 2006-2021 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
@ -27,16 +27,40 @@ import com.romraider.logger.ecu.definition.LoggerData;
*/
public final class EcuQueryData {
/**
* Return the length for an ECU Query item. The larger of either the
* number of addresses or the length defined by the data storagetype.
* @param ecuQuery - the ECU query to evaluate
* @return the length of the data type
*/
public final static int getDataLength(EcuQuery ecuQuery) {
return getDataLength(ecuQuery.getLoggerData());
// A query has its data length encoded in the definition using either
// the length="#" attribute of an address element or, by the
// storagetype="?" attribute in a conversion element.
final int addressLength = ecuQuery.getAddresses().length;
int dataTypeLength = getDataLength(ecuQuery.getLoggerData());
if (addressLength > dataTypeLength) {
dataTypeLength = addressLength;
}
return dataTypeLength;
}
/**
* Return the length for an Logger Data item.
* @param loggerData - the Logger Data to evaluate
* @return the length of the data type
*/
public final static int getDataLength(LoggerData loggerData) {
final String dataType =
loggerData.getSelectedConvertor().getDataType().toLowerCase();
return getDataLength(dataType);
}
/**
* Return the length for a Data type, int8, uint8, int16, etc.
* @param dataType - the Data type string to evaluate
* @return the length of the data type
*/
public final static int getDataLength(String dataType) {
int dataLength = 1;
if (dataType.contains("int16")) {
@ -48,6 +72,4 @@ public final class EcuQueryData {
}
return dataLength;
}
private EcuQueryData() {}
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2015 RomRaider.com
* Copyright (C) 2006-2021 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
@ -19,6 +19,8 @@
package com.romraider.logger.ecu.comms.query;
import static com.romraider.util.HexUtil.hexToInt;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@ -35,10 +37,18 @@ public final class EcuQueryRangeTest {
Logger.getLogger(EcuQueryRangeTest.class);
private final Collection<EcuQuery> queries;
private int datalength;
private int maxLength;
public EcuQueryRangeTest(Collection<EcuQuery> queries) {
/**
* Initialize the class with a collection of queries and the maximum
* distance between the lowest and highest allowed.
* @param queries - collection of queries
* @param maxLength - the maximum data length
*/
public EcuQueryRangeTest(Collection<EcuQuery> queries, int maxLength) {
this.queries = queries;
this.maxLength = maxLength;
}
/**
@ -58,28 +68,30 @@ public final class EcuQueryRangeTest {
int lowestAddress = Integer.MAX_VALUE;
int highestAddress = 0;
for (EcuQuery query : queryList) {
int dataSize = EcuQueryData.getDataLength(query);
final int address = Integer.parseInt(query.getHex(), 16);
if (address < lowestAddress) {
lowestAddress = address;
newQuery.clear();
newQuery.add(query);
final int dataTypeLength = EcuQueryData.getDataLength(query);
for (int i = 0; i < dataTypeLength; i++) {
int address = hexToInt(query.getAddresses()[0]) + i;
if (address < lowestAddress) {
lowestAddress = address;
newQuery.clear();
newQuery.add(query);
}
if (address > highestAddress) {
highestAddress = address;
}
LOGGER.trace(
String.format(
"addr:%d size:%d lowest:%d highest:%d",
address, highestAddress - lowestAddress + 1,
lowestAddress, highestAddress));
}
if (address > highestAddress) {
highestAddress = address + dataSize - 1;
}
LOGGER.trace(
String.format(
"addr:%d size:%d lowest:%d highest:%d",
address, dataSize, lowestAddress, highestAddress));
}
datalength = highestAddress - lowestAddress;
if (datalength <= 128) {
datalength ++;
return newQuery;
datalength = highestAddress - lowestAddress + 1;
if (datalength > maxLength) {
datalength = 0;
newQuery.clear();
}
datalength = 0;
return null;
return newQuery;
}
/**

View File

@ -36,24 +36,24 @@ import com.romraider.util.SettingsManager;
import com.romraider.xml.RomAttributeParser;
public class DataCell implements Serializable {
private static final long serialVersionUID = 1111479947434817639L;
private static final Logger LOGGER = Logger.getLogger(DataCell.class);
private static final long serialVersionUID = 1111479947434817639L;
private static final Logger LOGGER = Logger.getLogger(DataCell.class);
//View we need to keep up to date
private DataCellView view = null;
private Table table;
//This sounds like a View property, but the manipulations
//functions depend on this, so its better to put it here
private boolean isSelected = false;
private double binValue = 0.0;
private double originalValue = 0.0;
private double compareToValue = 0.0;
private String liveValue = Settings.BLANK;
private String staticText = null;
private Rom rom;
//Index within table
private int index;
@ -73,24 +73,24 @@ public class DataCell implements Serializable {
public DataCell(Table table, int index, Rom rom) {
this(table, rom);
this.index = index;
updateBinValueFromMemory();
updateBinValueFromMemory();
this.originalValue = this.binValue;
registerDataCell(this);
}
public void setTable(Table t) {
this.table = t;
this.table = t;
}
public void setRom(Rom rom) {
this.rom = rom;
this.rom = rom;
}
public byte[] getBinary() {
return rom.getBinary();
return rom.getBinary();
}
private double getValueFromMemory(int index) {
double dataValue = 0.0;
byte[] input = getBinary();
@ -99,8 +99,8 @@ public class DataCell implements Serializable {
int ramOffset = table.getRamOffset();
int storageAddress = table.getStorageAddress();
boolean signed = table.isSignedData();
// populate data cells
if (storageType == Settings.STORAGE_TYPE_FLOAT) { //float storage type
byte[] byteValue = new byte[4];
@ -111,7 +111,7 @@ public class DataCell implements Serializable {
dataValue = RomAttributeParser.byteToFloat(byteValue, table.getEndian(), table.getMemModelEndian());
} else if (storageType == Settings.STORAGE_TYPE_MOVI20 ||
storageType == Settings.STORAGE_TYPE_MOVI20S) { // when data is in MOVI20 instruction
storageType == Settings.STORAGE_TYPE_MOVI20S) { // when data is in MOVI20 instruction
dataValue = RomAttributeParser.parseByteValue(input,
endian,
storageAddress + index * 3 - ramOffset,
@ -119,78 +119,78 @@ public class DataCell implements Serializable {
signed);
} else { // integer storage type
if(table.getBitMask() == 0) {
dataValue = RomAttributeParser.parseByteValue(input,
endian, storageAddress + index * storageType - ramOffset,
storageType, signed);
}
else {
dataValue = RomAttributeParser.parseByteValueMasked(input, endian,
storageAddress + index * storageType - ramOffset,
storageType, signed, table.getBitMask());
}
if(table.getBitMask() == 0) {
dataValue = RomAttributeParser.parseByteValue(input,
endian, storageAddress + index * storageType - ramOffset,
storageType, signed);
}
else {
dataValue = RomAttributeParser.parseByteValueMasked(input, endian,
storageAddress + index * storageType - ramOffset,
storageType, signed, table.getBitMask());
}
}
return dataValue;
}
private double getValueFromMemory() {
if (table.getDataLayout() == Table.DataLayout.BOSCH_SUBTRACT) {
//Bosch Motronic subtract method
double dataValue = Math.pow(2, 8 * table.getStorageType());
for (int j = table.data.length - 1; j >= index; j--) {
dataValue -= getValueFromMemory(j);
}
return dataValue;
}
else {
private double getValueFromMemory() {
if (table.getDataLayout() == Table.DataLayout.BOSCH_SUBTRACT) {
//Bosch Motronic subtract method
double dataValue = Math.pow(2, 8 * table.getStorageType());
for (int j = table.data.length - 1; j >= index; j--) {
dataValue -= getValueFromMemory(j);
}
return dataValue;
}
else {
return getValueFromMemory(index);
}
}
}
public void saveBinValueInFile() {
if (table.getName().contains("Checksum Fix")) return;
public void saveBinValueInFile() {
if (table.getName().contains("Checksum Fix")) return;
byte[] binData = getBinary();
int userLevel = table.getUserLevel();
int storageType = table.getStorageType();
int userLevel = table.getUserLevel();
int storageType = table.getStorageType();
Endian endian = table.getEndian();
int ramOffset = table.getRamOffset();
int storageAddress = table.getStorageAddress();
boolean isBoschSubtract = table.getDataLayout() == Table.DataLayout.BOSCH_SUBTRACT;
double crossedValue = 0;
double crossedValue = 0;
//Do reverse cross referencing in for Bosch Subtract Axis array
if(isBoschSubtract) {
for (int i = table.data.length - 1; i >=index ; i--) {
if(i == index)
crossedValue -= table.data[i].getBinValue();
else if(i == table.data.length - 1)
crossedValue = Math.pow(2, 8 * storageType) - getValueFromMemory(i);
else {
crossedValue -= getValueFromMemory(i);
}
}
}
if (userLevel <= getSettings().getUserLevel() && (userLevel < 5 || getSettings().isSaveDebugTables()) ) {
if(isBoschSubtract) {
for (int i = table.data.length - 1; i >=index ; i--) {
if(i == index)
crossedValue -= table.data[i].getBinValue();
else if(i == table.data.length - 1)
crossedValue = Math.pow(2, 8 * storageType) - getValueFromMemory(i);
else {
crossedValue -= getValueFromMemory(i);
}
}
}
if (userLevel <= getSettings().getUserLevel() && (userLevel < 5 || getSettings().isSaveDebugTables()) ) {
// determine output byte values
byte[] output;
int mask = table.getBitMask();
int mask = table.getBitMask();
if (storageType != Settings.STORAGE_TYPE_FLOAT) {
int finalValue = 0;
int finalValue = 0;
// convert byte values
if(table.isStaticDataTable() && storageType > 0) {
LOGGER.warn("Static data table: " + table.toString() + ", storageType: "+storageType);
try {
finalValue = Integer.parseInt(getStaticText());
LOGGER.warn("Static data table: " + table.toString() + ", storageType: "+storageType);
try {
finalValue = Integer.parseInt(getStaticText());
} catch (NumberFormatException ex) {
LOGGER.error("Error parsing static data table value: " + getStaticText(), ex);
LOGGER.error("Validate the table definition storageType and data value.");
@ -200,143 +200,143 @@ public class DataCell implements Serializable {
// Do not save the value.
//LOGGER.debug("The static data table value will not be saved.");
return;
} else {
finalValue = (int) (isBoschSubtract ? crossedValue : getBinValue());
} else {
finalValue = (int) (isBoschSubtract ? crossedValue : getBinValue());
}
if(mask != 0) {
// Shift left again
finalValue = finalValue << ByteUtil.firstOneOfMask(mask);
}
if(mask != 0) {
// Shift left again
finalValue = finalValue << ByteUtil.firstOneOfMask(mask);
}
output = RomAttributeParser.parseIntegerValue(finalValue, endian, storageType);
int byteLength = storageType;
if (storageType == Settings.STORAGE_TYPE_MOVI20 ||
storageType == Settings.STORAGE_TYPE_MOVI20S) { // when data is in MOVI20 instruction
byteLength = 3;
storageType == Settings.STORAGE_TYPE_MOVI20S) { // when data is in MOVI20 instruction
byteLength = 3;
}
//If mask enabled, only change bits within the mask
if(mask != 0) {
int tempBitMask = 0;
for (int z = 0; z < byteLength; z++) { // insert into file
tempBitMask = mask;
//Trim mask depending on byte, from left to right
tempBitMask = (tempBitMask & (0xFF << 8 * (byteLength - 1 - z))) >> 8*(byteLength - 1 - z);
// Delete old bits
binData[index * byteLength + z + storageAddress - ramOffset] &= ~tempBitMask;
// Overwrite
binData[index * byteLength + z + storageAddress - ramOffset] |= output[z];
}
int tempBitMask = 0;
for (int z = 0; z < byteLength; z++) { // insert into file
tempBitMask = mask;
//Trim mask depending on byte, from left to right
tempBitMask = (tempBitMask & (0xFF << 8 * (byteLength - 1 - z))) >> 8*(byteLength - 1 - z);
// Delete old bits
binData[index * byteLength + z + storageAddress - ramOffset] &= ~tempBitMask;
// Overwrite
binData[index * byteLength + z + storageAddress - ramOffset] |= output[z];
}
}
//No Masking
else {
for (int z = 0; z < byteLength; z++) { // insert into file
binData[index * byteLength + z + storageAddress - ramOffset] = output[z];
}
for (int z = 0; z < byteLength; z++) { // insert into file
binData[index * byteLength + z + storageAddress - ramOffset] = output[z];
}
}
} else { // float
// convert byte values
output = RomAttributeParser.floatToByte((float) getBinValue(), endian, table.getMemModelEndian());
for (int z = 0; z < 4; z++) { // insert in to file
binData[index * 4 + z + storageAddress - ramOffset] = output[z];
}
}
}
//On the Bosch substract model, we need to update all previous cells, because they depend on our value
if(isBoschSubtract && index > 0) table.data[index-1].saveBinValueInFile();
checkForDataUpdates();
checkForDataUpdates();
}
public void registerDataCell(DataCell cell) {
int memoryIndex = getMemoryStartAddress(cell);
if (rom.byteCellMapping.containsKey(memoryIndex))
{
rom.byteCellMapping.get(memoryIndex).add(cell);
}
else {
LinkedList<DataCell> l = new LinkedList<DataCell>();
l.add(cell);
rom.byteCellMapping.put(memoryIndex, l);
}
int memoryIndex = getMemoryStartAddress(cell);
if (rom.byteCellMapping.containsKey(memoryIndex))
{
rom.byteCellMapping.get(memoryIndex).add(cell);
}
else {
LinkedList<DataCell> l = new LinkedList<DataCell>();
l.add(cell);
rom.byteCellMapping.put(memoryIndex, l);
}
}
public void checkForDataUpdates() {
int memoryIndex = getMemoryStartAddress(this);
if (rom.byteCellMapping.containsKey(memoryIndex)){
for(DataCell c : rom.byteCellMapping.get(memoryIndex)) {
c.updateBinValueFromMemory();
}
}
public void checkForDataUpdates() {
int memoryIndex = getMemoryStartAddress(this);
if (rom.byteCellMapping.containsKey(memoryIndex)){
for(DataCell c : rom.byteCellMapping.get(memoryIndex)) {
c.updateBinValueFromMemory();
}
}
}
public static int getMemoryStartAddress(DataCell cell) {
Table t = cell.getTable();
return t.getStorageAddress() + cell.getIndexInTable() * t.getStorageType() - t.getRamOffset();
Table t = cell.getTable();
return t.getStorageAddress() + cell.getIndexInTable() * t.getStorageType() - t.getRamOffset();
}
public Settings getSettings()
{
return SettingsManager.getSettings();
}
public void setSelected(boolean selected) {
if(!table.isStaticDataTable() && this.isSelected != selected) {
this.isSelected = selected;
if(view!=null) {
ECUEditorManager.getECUEditor().getTableToolBar().updateTableToolBar(table);
view.drawCell();
ECUEditorManager.getECUEditor().getTableToolBar().updateTableToolBar(table);
view.drawCell();
}
}
}
public boolean isSelected() {
return isSelected;
return isSelected;
}
public void updateBinValueFromMemory() {
this.binValue = getValueFromMemory();
updateView();
this.binValue = getValueFromMemory();
updateView();
}
public void setDataView(DataCellView v) {
view = v;
view = v;
}
public int getIndexInTable() {
return index;
return index;
}
private void updateView() {
if(view != null)
view.drawCell();
if(view != null)
view.drawCell();
}
public Table getTable() {
return this.table;
return this.table;
}
public String getStaticText() {
return staticText;
return staticText;
}
public String getLiveValue() {
return this.liveValue;
}
public void setLiveDataTraceValue(String liveValue) {
if(this.liveValue != liveValue) {
this.liveValue = liveValue;
@ -347,18 +347,18 @@ public class DataCell implements Serializable {
public double getBinValue() {
return binValue;
}
public double getOriginalValue() {
return originalValue;
return originalValue;
}
public double getCompareToValue() {
return compareToValue;
return compareToValue;
}
public double getRealValue() {
if(table.getCurrentScale() == null) return binValue;
if(table.getCurrentScale() == null) return binValue;
return JEPUtil.evaluate(table.getCurrentScale().getExpression(), binValue);
}
@ -408,9 +408,9 @@ public class DataCell implements Serializable {
if(binValue == newBinValue || table.locked || table.getName().contains("Checksum Fix")) {
return;
}
if (table.userLevel > getSettings().getUserLevel())
throw new UserLevelException(table.userLevel);
if (table.userLevel > getSettings().getUserLevel())
throw new UserLevelException(table.userLevel);
double checkedValue = newBinValue;
@ -493,20 +493,21 @@ public class DataCell implements Serializable {
this.compareToValue = compareCell.originalValue;
}
}
public void multiply(double factor) throws UserLevelException {
if(table.getCurrentScale().getName().equals("Raw Value"))
setBinValue(binValue * factor);
public void multiply(double factor) throws UserLevelException {
if(table.getCurrentScale().getCategory().equals("Raw Value"))
setBinValue(binValue * factor);
else {
String newValue = (getRealValue() * factor) + "";
//We need to convert from dot to comma, in the case of EU Format. This is because getRealValue to String has dot notation.
//We need to convert from dot to comma, in the case of EU Format.
// This is because getRealValue to String has dot notation.
if(NumberUtil.getSeperator() == ',') newValue = newValue.replace('.', ',');
setRealValue(newValue);
setRealValue(newValue);
}
}
}
@Override
public boolean equals(Object other) {
if(other == null) {

View File

@ -29,6 +29,7 @@ public class Scale implements Serializable {
private static final long serialVersionUID = 5836610685159474795L;
private String category = "Raw Value";
private String name = "Raw Value";
private String unit = "raw value";
private String expression = "x";
@ -41,31 +42,37 @@ public class Scale implements Serializable {
@Override
public String toString() {
return "\n ---- Scale ----" +
"\n Name: " + getName() +
"\n Expression: " + getExpression() +
"\n Byte Expression: " + getByteExpression() +
"\n Unit: " + getUnit() +
"\n Format: " + getFormat() +
"\n Coarse Increment: " + getCoarseIncrement() +
"\n Fine Increment: " + getFineIncrement() +
"\n Min: " + getMin() +
"\n Max: " + getMax() +
"\n ---- End Scale ----\n";
return "\n ---- Scale ----" +
"\n Category: " + getCategory() +
"\n Name: " + getName() +
"\n Expression: " + getExpression() +
"\n Byte Expression: " + getByteExpression() +
"\n Unit: " + getUnit() +
"\n Format: " + getFormat() +
"\n Coarse Increment: " + getCoarseIncrement() +
"\n Fine Increment: " + getFineIncrement() +
"\n Min: " + getMin() +
"\n Max: " + getMax() +
"\n ---- End Scale ----\n";
}
public boolean validate() {
if(expression.equals("x") && byteExpression.equals("x")) return true;
if(expression.equals("x") && byteExpression.equals("x")) return true;
double startValue = 5;
double toReal = JEPUtil.evaluate(getExpression(), startValue); // convert real world value of "5"
// convert real world value of "5"
double toReal = JEPUtil.evaluate(getExpression(), startValue);
double endValue = JEPUtil.evaluate(getByteExpression(), toReal);
// if real to byte doesn't equal 5, report conflict
if (Math.abs(endValue - startValue) > .001) return false;
else return true;
}
public void setCategory(String category) {
this.category = category;
}
public String getUnit() {
return unit;
}
@ -128,6 +135,22 @@ public class Scale implements Serializable {
this.fineIncrement = fineIncrement;
}
/**
* <b>category</b> is used to group like scalings, such as Metric,
* Imperial, etc. (case insensitive).<br>
* This is the value shown in the Table Tool bar scaling selection list.
* @return <b>category</b> name
*/
public String getCategory() {
return category;
}
/**
* <b>name</b> is defined in a scalingbase element (case insensitive).<br>
* <b>name</b> is used by the base attribute in a scaling element definition
* to inherit from a scalingbase.
* @return <b>name</b> as defined in scalingbase
*/
public String getName() {
return name;
}
@ -169,11 +192,26 @@ public class Scale implements Serializable {
Scale otherScale = (Scale)other;
if( (null == this.getCategory() && null == otherScale.getCategory())
|| (this.getCategory().isEmpty() && otherScale.getCategory().isEmpty()) )
{
;// Skip Category compare if Category is null or empty.
} else
{
if(!this.getCategory().equalsIgnoreCase(otherScale.getCategory()))
{
return false;
}
}
if( (null == this.getName() && null == otherScale.getName())
|| (this.getName().isEmpty() && otherScale.getName().isEmpty()) ) {
|| (this.getName().isEmpty() && otherScale.getName().isEmpty()) )
{
;// Skip name compare if name is null or empty.
} else {
if(!this.getName().equalsIgnoreCase(otherScale.getName())) {
} else
{
if(!this.getName().equalsIgnoreCase(otherScale.getName()))
{
return false;
}
}
@ -223,4 +261,4 @@ public class Scale implements Serializable {
return false;
}
}
}
}

View File

@ -41,31 +41,31 @@ public abstract class Table implements Serializable {
protected TableView tableView;
protected TableFrame tableFrame;
protected String name;
protected String category = "Other";
protected String description = Settings.BLANK;
protected Vector<Scale> scales = new Vector<Scale>();
protected Scale curScale;
protected PresetManager presetManager;
protected int storageAddress;
protected int storageType;
protected boolean signed;
protected Settings.Endian endian = Settings.Endian.BIG;
protected boolean flip;
protected DataLayout dataLayout = DataLayout.DEFAULT; //DataCell Ordering
protected DataLayout dataLayout = DataLayout.DEFAULT; //DataCell Ordering
protected DataCell[] data = new DataCell[1];
protected boolean beforeRam = false;
protected int ramOffset = 0;
protected int userLevel = 0;
protected boolean locked = false;
protected String logParam = Settings.BLANK;
private int bitMask = 0;
private int bitMask = 0;
protected double minAllowedBin = 0.0;
protected double maxAllowedBin = 0.0;
@ -75,39 +75,39 @@ public abstract class Table implements Serializable {
protected double maxCompare = 0.0;
protected double minCompare = 0.0;
protected boolean staticDataTable = false;
protected boolean staticDataTable = false;
private Table compareTable = null;
protected Settings.DataType compareValueType = Settings.DataType.BIN;
public enum DataLayout {
DEFAULT,
BOSCH_SUBTRACT
DEFAULT,
BOSCH_SUBTRACT
}
public void setTableView(TableView v) {
this.tableView = v;
this.tableView = v;
}
public TableView getTableView() {
return this.tableView;
return this.tableView;
}
public void setTableFrame(TableFrame v) {
this.tableFrame = v;
this.tableFrame = v;
}
public TableFrame getTableFrame() {
return this.tableFrame;
return this.tableFrame;
}
public DataCell[] getData() {
return data;
}
public void addStaticDataCell(String s) {
setStaticDataTable(true);
DataCell c = new DataCell(this, s, null);
setStaticDataTable(true);
DataCell c = new DataCell(this, s, null);
for(int i = 0; i < data.length; i++) {
if(data[i] == null) {
data[i] = c;
@ -115,36 +115,36 @@ public abstract class Table implements Serializable {
}
}
}
//Cleans up all references to avoid data leaks
public void clearData() {
if(data != null) {
for(int i=0;i<getDataSize();i++) {
if(data[i]!=null) {
data[i].setTable(null);
data[i].setRom(null);
data[i] = null;
}
}
data = null;
}
if(data != null) {
for(int i=0;i<getDataSize();i++) {
if(data[i]!=null) {
data[i].setTable(null);
data[i].setRom(null);
data[i] = null;
}
}
data = null;
}
}
public void setData(DataCell[] data) {
this.data = data;
}
public int getRamOffset() {
return this.ramOffset;
return this.ramOffset;
}
public void populateTable(Rom rom) throws ArrayIndexOutOfBoundsException, IndexOutOfBoundsException {
if(isStaticDataTable()) return;
validateScaling();
// temporarily remove lock;
if(isStaticDataTable()) return;
validateScaling();
// temporarily remove lock;
boolean tempLock = locked;
locked = false;
@ -152,16 +152,16 @@ public abstract class Table implements Serializable {
this.ramOffset = rom.getRomID().getRamOffset();
}
for (int i = 0; i < data.length; i++) {
data[i] = new DataCell(this, i, rom);
for (int i = 0; i < data.length; i++) {
data[i] = new DataCell(this, i, rom);
}
// reset locked status
locked = tempLock;
calcCellRanges();
//Add Raw Scale
addScale(new Scale());
//Add Raw Scale
addScale(new Scale());
}
public abstract TableType getType();
@ -175,7 +175,7 @@ public abstract class Table implements Serializable {
}
public void setCategory(String category) {
category = category.trim().replace(" //", "//").replace("// ", "//");
category = category.trim().replace(" //", "//").replace("// ", "//");
this.category = category;
}
@ -186,21 +186,21 @@ public abstract class Table implements Serializable {
public void setDescription(String description) {
this.description = description;
}
//Gets called by toolbar
public void updateIncrementDecrementValues(double fineInc, double courseInc) {
this.curScale.setCoarseIncrement(courseInc);
this.curScale.setFineIncrement(fineInc);
public void updateIncrementDecrementValues(double fineInc, double courseInc) {
this.curScale.setCoarseIncrement(courseInc);
this.curScale.setFineIncrement(fineInc);
}
public Scale getCurrentScale() {
return this.curScale;
}
public Scale getScale(String scaleName) throws NameNotFoundException {
for (Scale scale : scales) {
if (scale.getName().equalsIgnoreCase(scaleName)) {
if (scale.getCategory().equalsIgnoreCase(scaleName)) {
return scale;
}
}
@ -214,7 +214,7 @@ public abstract class Table implements Serializable {
public void addScale(Scale scale) {
// look for scale, replace or add new
for (int i = 0; i < scales.size(); i++) {
if (scales.get(i).getName().equalsIgnoreCase(scale.getName())) {
if (scales.get(i).getCategory().equalsIgnoreCase(scale.getCategory())) {
scales.remove(i);
break;
}
@ -224,12 +224,12 @@ public abstract class Table implements Serializable {
if(null == curScale) {
this.curScale = scale;
}
if(SettingsManager.getSettings().getDefaultScale().equalsIgnoreCase(scale.getName())) {
if(SettingsManager.getSettings().getDefaultScale().equalsIgnoreCase(scale.getCategory())) {
this.curScale = scale;
}
else if("Default".equalsIgnoreCase(scale.getName())) {
this.curScale = scale;
else if("Default".equalsIgnoreCase(scale.getCategory())) {
this.curScale = scale;
}
}
@ -289,7 +289,7 @@ public abstract class Table implements Serializable {
public String getLogParam() {
return logParam;
}
public String getLogParamString() {
return getName()+ ":" + getLogParam();
}
@ -312,21 +312,21 @@ public abstract class Table implements Serializable {
}
return name;
}
public void setName(String n) {
this.name = n;
this.name = n;
}
public String getName() {
return name;
return name;
}
public StringBuffer getTableAsString() {
StringBuffer output = new StringBuffer(Settings.BLANK);
for (int i = 0; i < data.length; i++) {
if(data[i]!= null)
output.append(NumberUtil.stringValue(data[i].getRealValue()));
output.append(NumberUtil.stringValue(data[i].getRealValue()));
if (i < data.length - 1) {
output.append(Settings.TAB);
@ -334,7 +334,7 @@ public abstract class Table implements Serializable {
}
return output;
}
//Faster version of equals where data doesnt matter (yet)
public boolean equalsWithoutData(Object other) {
try {
@ -351,46 +351,46 @@ public abstract class Table implements Serializable {
}
Table otherTable = (Table)other;
if(storageAddress != otherTable.storageAddress) {
return false;
return false;
}
if(!this.name.equals(otherTable.name)) {
return false;
return false;
}
if(this.data.length != otherTable.data.length)
{
return false;
}
if (this.bitMask != otherTable.bitMask) {
return false;
}
if (this.bitMask != otherTable.bitMask) {
return false;
}
return true;
} catch(Exception ex) {
// TODO: Log Exception.
return false;
}
}
@Override
public boolean equals(Object other) {
try {
boolean withoutData = equalsWithoutData(other);
if(!withoutData) return false;
Table otherTable = (Table)other;
// Compare Bin Values
for(int i=0 ; i < this.data.length ; i++) {
if(! this.data[i].equals(otherTable.data[i])) {
return false;
}
}
return true;
} catch(Exception ex) {
// TODO: Log Exception.
@ -414,7 +414,7 @@ public abstract class Table implements Serializable {
return JEPUtil.evaluate(getCurrentScale().getExpression(), getMinAllowedBin());
}
protected void calcValueRange() {
protected void calcValueRange() {
if (getStorageType() != Settings.STORAGE_TYPE_FLOAT) {
if (isSignedData()) {
switch (getStorageType()) {
@ -441,15 +441,15 @@ public abstract class Table implements Serializable {
}
}
else {
if(bitMask == 0) {
maxAllowedBin = (Math.pow(256, getStorageType()) - 1);
}
else {
maxAllowedBin =(int)(Math.pow(2,ByteUtil.lengthOfMask(bitMask)) - 1);
}
minAllowedBin = 0.0;
if(bitMask == 0) {
maxAllowedBin = (Math.pow(256, getStorageType()) - 1);
}
else {
maxAllowedBin =(int)(Math.pow(2,ByteUtil.lengthOfMask(bitMask)) - 1);
}
minAllowedBin = 0.0;
}
} else {
maxAllowedBin = Float.MAX_VALUE;
@ -463,37 +463,37 @@ public abstract class Table implements Serializable {
}
public void calcCellRanges() {
if(data.length > 0) {
double binMax = data[0].getBinValue();
double binMin = data[0].getBinValue();
double compareMax = data[0].getCompareValue();
double compareMin = data[0].getCompareValue();
for(DataCell cell : data) {
// Calc bin
if(binMax < cell.getBinValue()) {
binMax = cell.getBinValue();
}
if(binMin > cell.getBinValue()) {
binMin = cell.getBinValue();
}
// Calc compare
double compareValue = cell.getCompareValue();
if(compareMax < compareValue) {
compareMax = compareValue;
}
if(compareMin > compareValue) {
compareMin = compareValue;
}
}
setMaxBin(binMax);
setMinBin(binMin);
setMaxCompare(compareMax);
setMinCompare(compareMin);
}
if(data.length > 0) {
double binMax = data[0].getBinValue();
double binMin = data[0].getBinValue();
double compareMax = data[0].getCompareValue();
double compareMin = data[0].getCompareValue();
for(DataCell cell : data) {
// Calc bin
if(binMax < cell.getBinValue()) {
binMax = cell.getBinValue();
}
if(binMin > cell.getBinValue()) {
binMin = cell.getBinValue();
}
// Calc compare
double compareValue = cell.getCompareValue();
if(compareMax < compareValue) {
compareMax = compareValue;
}
if(compareMin > compareValue) {
compareMin = compareValue;
}
}
setMaxBin(binMax);
setMinBin(binMin);
setMaxCompare(compareMax);
setMinCompare(compareMin);
}
}
public double getMaxBin() {
@ -559,14 +559,14 @@ public abstract class Table implements Serializable {
cell.undo();
}
}
abstract public byte[] saveFile(byte[] binData);
public void setValues(String name, String value) {
if(presetManager == null) presetManager = new PresetManager(this);
presetManager.setValues(name, value);
if(presetManager == null) presetManager = new PresetManager(this);
presetManager.setValues(name, value);
}
public boolean isBeforeRam() {
return beforeRam;
}
@ -574,46 +574,46 @@ public abstract class Table implements Serializable {
public void setBeforeRam(boolean beforeRam) {
this.beforeRam = beforeRam;
}
public void setDataLayout(String s) {
if(s.trim().equalsIgnoreCase("bosch_subtract")) {
setDataLayout(DataLayout.BOSCH_SUBTRACT);
}
else {
setDataLayout(DataLayout.DEFAULT);
}
if(s.trim().equalsIgnoreCase("bosch_subtract")) {
setDataLayout(DataLayout.BOSCH_SUBTRACT);
}
else {
setDataLayout(DataLayout.DEFAULT);
}
}
public void setDataLayout(DataLayout m) {
this.dataLayout = m;
}
public DataLayout getDataLayout() {
return this.dataLayout;
}
public void setStringMask(String stringMask) {
int mask = ByteUtil.parseUnsignedInt(stringMask, 16);
setBitMask(mask);
}
public void setBitMask(int mask) {
if(mask == 0) return;
//Clamp mask to max size
bitMask = (int) Math.min(mask, Math.pow(2,getStorageType()*8)-1);
calcValueRange();
}
public int getBitMask() {
return bitMask;
}
public void setStringMask(String stringMask) {
int mask = ByteUtil.parseUnsignedInt(stringMask, 16);
setBitMask(mask);
}
public void setBitMask(int mask) {
if(mask == 0) return;
//Clamp mask to max size
bitMask = (int) Math.min(mask, Math.pow(2,getStorageType()*8)-1);
calcValueRange();
}
public int getBitMask() {
return bitMask;
}
public void validateScaling() {
if (getType() != TableType.SWITCH) {
if (getType() != TableType.SWITCH) {
for(Scale scale : scales) {
if (!scale.validate()) {
TableView.showBadScalePopup(this, scale);
TableView.showBadScalePopup(this, scale);
}
}
}
@ -639,32 +639,32 @@ public abstract class Table implements Serializable {
calcCellRanges();
if(tableView != null) tableView.drawTable();
}
public void clearSelection() {
if(data!=null) {
for (DataCell cell : data) {
if(data!=null) {
for (DataCell cell : data) {
cell.setSelected(false);
}
}
}
}
public void selectCellAt(int y) {
if(y >= 0 && y < data.length) {
clearSelection();
data[y].setSelected(true);
if(tableView!=null) tableView.highlightBeginY = y;
if(tableView!=null) tableView.highlightBeginY = y;
}
}
public void selectCellAtWithoutClear(int y) {
if(y >= 0 && y < data.length) {
data[y].setSelected(true);
if(tableView!=null)tableView.highlightBeginY = y;
if(tableView!=null)tableView.highlightBeginY = y;
}
}
public void verticalInterpolate() throws UserLevelException{
horizontalInterpolate();
horizontalInterpolate();
}
public void horizontalInterpolate() throws UserLevelException {
@ -679,38 +679,38 @@ public abstract class Table implements Serializable {
coords[1] = i;
}
}
if (coords[1] - coords[0] > 1) {
double y1, y2;
y1 = tableData[coords[0]].getBinValue();
y2 = tableData[coords[1]].getBinValue();
for (int i = coords[0] + 1; i < coords[1]; ++i) {
float p = (float)((i - coords[0]))/(coords[1] - coords[0]);
float p = (float)((i - coords[0]))/(coords[1] - coords[0]);
data[i].setBinValue((y2*p)+(y1 *(1-p)));
}
}
}
}
public void interpolate() throws UserLevelException {
horizontalInterpolate();
}
public double linearInterpolation(double x, double x1, double x2, double y1, double y2) {
return (x1 == x2) ? 0.0 : (y1 + (x - x1) * (y2 - y1) / (x2 - x1));
}
public void increment(double increment) throws UserLevelException {
for (DataCell cell : data) {
if (cell.isSelected()) {
cell.increment(increment);
}
}
for (DataCell cell : data) {
if (cell.isSelected()) {
cell.increment(increment);
}
}
}
public void multiply(double factor) throws UserLevelException{
for (DataCell cell : data) {
if (cell.isSelected()) {
cell.multiply(factor);
public void multiply(double factor) throws UserLevelException{
for (DataCell cell : data) {
if (cell.isSelected()) {
cell.multiply(factor);
}
}
}
@ -724,7 +724,7 @@ public abstract class Table implements Serializable {
}
public abstract boolean isLiveDataSupported();
public int getUserLevel() {
return userLevel;
}
@ -737,10 +737,10 @@ public abstract class Table implements Serializable {
userLevel = 1;
}
}
public void setScaleByName(String scaleName) throws NameNotFoundException {
public void setScaleByCategory(String scaleName) throws NameNotFoundException {
for(Scale scale : scales) {
if(scale.getName().equalsIgnoreCase(scaleName)) {
if(scale.getCategory().equalsIgnoreCase(scaleName)) {
Scale currentScale = getCurrentScale();
if(currentScale == null || !currentScale.equals(scale)) {
this.setCurrentScale(scale);
@ -754,10 +754,10 @@ public abstract class Table implements Serializable {
public void setCurrentScale(Scale curScale) {
this.curScale = curScale;
if(tableView!=null) {
tableView.drawTable();
}
tableView.drawTable();
}
}
public Settings getSettings()
@ -781,13 +781,13 @@ public abstract class Table implements Serializable {
public void setCompareTable(Table compareTable) {
this.compareTable = compareTable;
if(tableView!= null)tableView.drawTable();
}
public void setCompareValueType(Settings.DataType compareValueType) {
this.compareValueType = compareValueType;
if(tableView!= null)tableView.drawTable();
}
@ -797,7 +797,7 @@ public abstract class Table implements Serializable {
public void colorCells() {
calcCellRanges();
if(tableView!=null)tableView.drawTable();
}

View File

@ -36,7 +36,7 @@ public class Table2D extends Table {
public Table1D getAxis() {
return axis;
}
public void setAxis(Table1D axis) {
this.axis = axis;
axis.setAxisParent(this);
@ -45,15 +45,15 @@ public class Table2D extends Table {
@Override
public String toString() {
return super.toString() + " (2D)";// + axis;
}
}
@Override
public void clearData() {
super.clearData();
axis.clearData();
axis=null;
super.clearData();
axis.clearData();
axis=null;
}
@Override
public void populateCompareValues(Table otherTable) {
if(null == otherTable || !(otherTable instanceof Table2D)) {
@ -77,7 +77,7 @@ public class Table2D extends Table {
}
@Override
public void populateTable(Rom rom) throws ArrayIndexOutOfBoundsException, IndexOutOfBoundsException {
public void populateTable(Rom rom) throws ArrayIndexOutOfBoundsException, IndexOutOfBoundsException {
axis.populateTable(rom);
super.populateTable(rom);
}
@ -94,10 +94,10 @@ public class Table2D extends Table {
super.undoAll();
axis.undoAll();
}
@Override
public byte[] saveFile(byte[] binData) {
public byte[] saveFile(byte[] binData) {
return binData;
}
@ -108,7 +108,7 @@ public class Table2D extends Table {
sb.append(getName()+ ":" + getLogParam());
return sb.toString();
}
@Override
public boolean isLiveDataSupported() {
return !isNullOrEmpty(axis.getLogParam());
@ -118,7 +118,7 @@ public class Table2D extends Table {
public boolean isButtonSelected() {
return true;
}
@Override
public void setCompareValueType(Settings.DataType compareValueType) {
super.setCompareValueType(compareValueType);
@ -129,50 +129,50 @@ public class Table2D extends Table {
public void setCurrentScale(Scale curScale) {
if(SettingsManager.getSettings().isScaleHeadersAndData() && !axis.isStaticDataTable()) {
try {
this.axis.setScaleByName(curScale.getName());
this.axis.setScaleByCategory(curScale.getCategory());
} catch (NameNotFoundException e) {
try {
this.axis.setScaleByName(SettingsManager.getSettings().getDefaultScale());
this.axis.setScaleByCategory(SettingsManager.getSettings().getDefaultScale());
} catch (NameNotFoundException e1) {
try {
this.axis.setScaleByName("Default");
try {
this.axis.setScaleByCategory("Default");
} catch (NameNotFoundException e2) {
e2.printStackTrace();
e2.printStackTrace();
}
}
}
}
this.curScale = curScale;
if(tableView != null) tableView.drawTable();
}
@Override
public void clearSelection() {
if(axis!=null)
axis.clearSelection();
if(axis!=null)
axis.clearSelection();
super.clearSelection();
}
@Override
public void setRealValue(String realValue) throws UserLevelException {
super.setRealValue(realValue);
axis.setRealValue(realValue);
}
@Override
public void increment(double increment) throws UserLevelException {
super.increment(increment);
axis.increment(increment);
super.increment(increment);
axis.increment(increment);
}
@Override
public void multiply(double factor) throws UserLevelException{
super.multiply(factor);
axis.multiply(factor);
public void multiply(double factor) throws UserLevelException{
super.multiply(factor);
axis.multiply(factor);
}
@Override
public void interpolate() throws UserLevelException {
super.interpolate();
@ -213,7 +213,7 @@ public class Table2D extends Table {
// Interpolate x axis in case the x axis in selected.
this.getAxis().horizontalInterpolate();
}
@Override
public StringBuffer getTableAsString() {
StringBuffer output = new StringBuffer(Settings.BLANK);
@ -273,5 +273,5 @@ public class Table2D extends Table {
// TODO: Log Exception.
return false;
}
}
}
}
}

View File

@ -42,11 +42,11 @@ public class Table3D extends Table {
public TableType getType() {
return Table.TableType.TABLE_3D;
}
public Table3DView getTableView() {
return (Table3DView) tableView;
return (Table3DView) tableView;
}
public Table1D getXAxis() {
return xAxis;
}
@ -104,24 +104,24 @@ public class Table3D extends Table {
public int getSizeY() {
return data[0].length;
}
@Override
public void clearData() {
for(DataCell[] column : data) {
for(DataCell cell : column) {
cell.setTable(null);
cell.setRom(null);
cell.setTable(null);
cell.setRom(null);
}
}
xAxis.clearData();
yAxis.clearData();
data = null;
xAxis=null;
yAxis=null;
xAxis.clearData();
yAxis.clearData();
data = null;
xAxis=null;
yAxis=null;
}
@Override
public StringBuffer getTableAsString() {
StringBuffer output = new StringBuffer(Settings.BLANK);
@ -135,8 +135,8 @@ public class Table3D extends Table {
for (int x = 0; x < getSizeX(); x++) {
output.append(NumberUtil.stringValue(data[x][y].getRealValue()));
output.append(NumberUtil.stringValue(data[x][y].getRealValue()));
if (x < getSizeX() - 1) {
output.append(Settings.TAB);
}
@ -152,9 +152,9 @@ public class Table3D extends Table {
@Override
public void populateTable(Rom rom) throws NullPointerException, ArrayIndexOutOfBoundsException, IndexOutOfBoundsException {
validateScaling();
// fill first empty cell
validateScaling();
// fill first empty cell
if (!beforeRam) {
this.ramOffset = rom.getRomID().getRamOffset();
}
@ -192,11 +192,11 @@ public class Table3D extends Table {
}
// reset locked status
locked = tempLock;
locked = tempLock;
calcCellRanges();
//Add Raw Scale
addScale(new Scale());
//Add Raw Scale
addScale(new Scale());
}
@Override
@ -301,7 +301,7 @@ public class Table3D extends Table {
@Override
public byte[] saveFile(byte[] binData) {
return binData;
return binData;
}
@Override
@ -330,81 +330,81 @@ public class Table3D extends Table {
if(SettingsManager.getSettings().isScaleHeadersAndData()) {
if(!xAxis.isStaticDataTable()) {
try {
this.xAxis.setScaleByName(curScale.getName());
this.xAxis.setScaleByCategory(curScale.getCategory());
} catch (NameNotFoundException e) {
try {
this.xAxis.setScaleByName(SettingsManager.getSettings().getDefaultScale());
this.xAxis.setScaleByCategory(SettingsManager.getSettings().getDefaultScale());
} catch (NameNotFoundException e1) {
try {
this.xAxis.setScaleByName("Default");
try {
this.xAxis.setScaleByCategory("Default");
} catch (NameNotFoundException e2) {
e2.printStackTrace();
e2.printStackTrace();
}
}
}
}
if(!yAxis.isStaticDataTable()) {
try {
this.yAxis.setScaleByName(curScale.getName());
this.yAxis.setScaleByCategory(curScale.getCategory());
} catch (NameNotFoundException e) {
try {
this.yAxis.setScaleByName(SettingsManager.getSettings().getDefaultScale());
this.yAxis.setScaleByCategory(SettingsManager.getSettings().getDefaultScale());
} catch (NameNotFoundException e1) {
try {
this.yAxis.setScaleByName("Default");
try {
this.yAxis.setScaleByCategory("Default");
} catch (NameNotFoundException e2) {
e2.printStackTrace();
e2.printStackTrace();
}
}
}
}
}
this.curScale = curScale;
this.curScale = curScale;
if(tableView!=null) tableView.drawTable();
}
private void setHighlightXY(int x, int y) {
if(tableView!=null) {
tableView.highlightBeginX = x;
tableView.highlightBeginY = y;
tableView.highlightBeginX = x;
tableView.highlightBeginY = y;
}
}
public void deSelectCellAt(int x, int y) {
clearSelection();
data[x][y].setSelected(false);
setHighlightXY(x,y);
}
public void selectCellAt(int x, int y) {
clearSelection();
data[x][y].setSelected(true);
setHighlightXY(x,y);
}
public void selectCellAtWithoutClear(int x, int y) {
data[x][y].setSelected(true);
setHighlightXY(x,y);
}
@Override
public void clearSelection() {
if(xAxis!=null)
xAxis.clearSelection();
if(yAxis!=null)
yAxis.clearSelection();
if(data!=null) {
for (int x = 0; x < getSizeX(); x++) {
for (int y = 0; y < getSizeY(); y++) {
data[x][y].setSelected(false);
}
}
}
if(xAxis!=null)
xAxis.clearSelection();
if(yAxis!=null)
yAxis.clearSelection();
if(data!=null) {
for (int x = 0; x < getSizeX(); x++) {
for (int y = 0; y < getSizeY(); y++) {
data[x][y].setSelected(false);
}
}
}
}
@Override
public void increment(double increment) throws UserLevelException {
for (int x = 0; x < getSizeX(); x++) {
@ -420,13 +420,13 @@ public class Table3D extends Table {
public void multiply(double factor) throws UserLevelException {
for (int x = 0; x < getSizeX(); x++) {
for (int y = 0; y < getSizeY(); y++) {
if (data[x][y].isSelected()) {
data[x][y].multiply(factor);
if (data[x][y].isSelected()) {
data[x][y].multiply(factor);
}
}
}
}
}
@Override
public void setRealValue(String realValue) throws UserLevelException {
for(DataCell[] column : data) {
@ -439,7 +439,7 @@ public class Table3D extends Table {
xAxis.setRealValue(realValue);
yAxis.setRealValue(realValue);
}
@Override
public void verticalInterpolate() throws UserLevelException {
int[] coords = { getSizeX(), getSizeY(), 0, 0};
@ -519,7 +519,7 @@ public class Table3D extends Table {
verticalInterpolate();
horizontalInterpolate();
}
@Override
public String getLogParamString() {
StringBuilder sb = new StringBuilder();
@ -587,5 +587,3 @@ public class Table3D extends Table {
}
}
}

View File

@ -0,0 +1,181 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2021 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.
*
* Encoding and decoding routines based on:
* https://github.com/fenugrec/nissutils/blob/master/cli_utils/
*/
package com.romraider.maps.checksum;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import com.romraider.util.HexUtil;
/**
* This class contains functions to encode and decoded data as well as
* calculate its CRC in Nissan fashion.
*/
public final class NcsCoDec {
public NcsCoDec() {
}
/**
* For the given inBuf, decode the data with the supplied code
* and return the decoded data
*/
public final byte[] nisDecode(ByteBuffer inBuf, int code) {
final ByteBuffer outBuf = ByteBuffer.allocate(inBuf.capacity()).order(ByteOrder.BIG_ENDIAN);
inBuf.rewind();
while (inBuf.hasRemaining()) {
outBuf.putInt(decode(inBuf.getInt(), code));
}
return outBuf.array();
}
/**
* For the given inBuf, encode the data with the supplied code
* and return the encoded data
*/
public final byte[] nisEncode(ByteBuffer inBuf, int code) {
final ByteBuffer outBuf = ByteBuffer.allocate(inBuf.capacity()).order(ByteOrder.BIG_ENDIAN);
inBuf.rewind();
while (inBuf.hasRemaining()) {
outBuf.putInt(encode(inBuf.getInt(), code));
}
return outBuf.array();
}
/**
* For the given encoded data, decode the data with the supplied code
* and return decoded data
*/
// https://github.com/fenugrec/nissutils/blob/master/cli_utils/nislib.c#dec1
private final int decode(int data, int code) {
final int dH = data >>> 16;
final int dL = data & 0xFFFF;
final int cH = code >>> 16;
final int cL = code & 0xFFFF;
final int kL = mess2(dH, dL, cL);
final int kH = mess1(dL, kL, cH);
return (kH << 16) | kL;
}
/**
* For the given data, encode the data with the supplied code
* and return the encoded data
*/
// https://github.com/fenugrec/nissutils/blob/master/cli_utils/nislib.c#enc1
private final int encode(int data, int code) {
final int dH = data >>> 16;
final int dL = data & 0xFFFF;
final int cH = code >>> 16;
final int cL = code & 0xFFFF;
final int kL = mess1(dH, dL, cH);
final int kH = mess2(dL, kL, cL);
return (kH << 16 | kL);
}
// https://github.com/fenugrec/nissutils/blob/master/cli_utils/nislib.c#mess1
private final int mess1(int a, int b, int x) {
final int var0 = (x + b) & 0xFFFF;
final int var1 = var0 << 2;
final int var2 = var1 >>> 16;
final int var3 = var2 + var0 + var1 - 1;
return (var3 ^ a) & 0xFFFF;
}
// https://github.com/fenugrec/nissutils/blob/master/cli_utils/nislib.c#mess2
private final int mess2(int a, int b, int x) {
final int var0 = (x + b) & 0xFFFF;
final int var1 = var0 << 1;
final int var2 = ((var1 >>> 16) + var0 + var1 - 1) & 0xFFFF;
final int var3 = var2 << 4;
final int var4 = var3 + (var3 >>> 16);
return (a ^ var4 ^ var2) & 0xFFFF;
}
/**
* For the given data, calculate the 16 bit CRC.
*/
// sub_15CC in 1ZN67A
public final short calcCrc(byte[] data) {
int r6;
int r5;
int crc = 0xffff;
for (int i = 0; i < data.length; i++) {
r5 = data[i];
for (int j = 0; j < 8; j++) {
r6 = crc & 1;
crc = crc >>> 1;
if(r6 != (r5 & 1)) {
crc = crc ^ 0x8408;
}
r5 = r5 >> 1;
}
}
return (short) crc;
}
/**
* Test the NisCoDec functions
*/
public static void main(String[] args) {
final NcsCoDec codec = new NcsCoDec();
String bin_text = "FFFF22E4000115F8000116A000011724000117C80002B9C4E00180F884F820088B1B62F0E7EC9625D91426209623656062637205645C60430274901D7501655C029C760560530624D20D420B75019013D60C029C9011A0040624E4AC644CB18BE5127F204F266EF66DF66CF66BF66AF6000B69F697B481050848035EFFFF22E4";
byte[] bin = HexUtil.asBytes(bin_text);
final int scode = 0xC2C0823F;
ByteBuffer data = ByteBuffer.allocate(bin.length).order(ByteOrder.BIG_ENDIAN).put(bin);
final byte[] dataEncoded = codec.nisEncode(data, scode);
short crc = codec.calcCrc(dataEncoded);
short invert = (short) ~crc;
short le = (short) (((invert << 8) | ((invert & 0xffff) >>> 8)) & 0xffff);
final byte[] crcCheck = new byte[dataEncoded.length + 2];
System.arraycopy(dataEncoded, 0, crcCheck, 0, dataEncoded.length);
crcCheck[crcCheck.length - 2] = (byte) (invert & 0xff);
crcCheck[crcCheck.length - 1] = (byte) ((invert & 0xffff) >>> 8);
short residue = codec.calcCrc(crcCheck);
System.out.println(String.format(
"Encode Test:%nbin data: %s%nscode: %08X%nencoded: %s%nCRC (D10D): %04X%n~CRC (2EF2): %04X%n" +
"little-endian ~CRC (F22E): %04X%nresidue: %04X",
HexUtil.asHex(bin), scode, HexUtil.asHex(dataEncoded), crc, invert, le,
residue));
String text = "34830000003030303030303041060431434D43375150443430310000000000000000005230303030434F4E332B0619022000005CAD04";
byte[] hex = HexUtil.asBytes(text);
residue = codec.calcCrc(hex);
System.out.println(String.format("%s%nCRC: %04X%n~CRC: %04X",
HexUtil.asHex(hex), residue, (short)~residue));
text = "348300000030FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9BC";
hex = HexUtil.asBytes(text);
residue = codec.calcCrc(hex);
System.out.println(String.format("%s%nCRC: %04X%n~CRC: %04X",
HexUtil.asHex(hex), residue, (short)~residue));
data.rewind();
data = ByteBuffer.allocate(dataEncoded.length).order(ByteOrder.BIG_ENDIAN).put(dataEncoded);
byte[] dataDecoded = codec.nisDecode(data, scode);
System.out.println(String.format("Decoded Data: %s",
HexUtil.asHex(dataDecoded)));
if(bin_text.equalsIgnoreCase(HexUtil.asHex(dataDecoded))) {
System.out.println("Decoded data matches input data");
}
else {
System.out.println("DATA DOES NOT MATCH !!!");
}
}
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2014 RomRaider.com
* Copyright (C) 2006-2021 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
@ -28,42 +28,44 @@ import com.romraider.maps.Scale;
public final class ScalesTableModel extends DefaultTableModel {
private static final long serialVersionUID = -5967359776053559125L;
private static final String[] colNames = {
"Name", "Expression", "Byte Expression",
"Category", "Name", "Expression", "Byte Expression",
"Unit", "Format", "Coarse", "Fine", "Min", "Max"};
private Vector<Scale> scales;
@Override
public final int getColumnCount() {
return colNames.length;
}
@Override
public final String getColumnName(int column) {
return colNames[column].toString();
}
@Override
public final Object getValueAt(int row, int column) {
if (null != scales) {
final Scale scale = scales.get(row);
switch (column) {
case 0:
return scale.getCategory();
case 1:
return scale.getName();
case 1:
case 2:
return scale.getExpression();
case 2:
return scale.getByteExpression();
case 3:
return scale.getByteExpression();
case 4:
return scale.getUnit();
case 4:
case 5:
return scale.getFormat();
case 5:
return scale.getCoarseIncrement();
case 6:
return scale.getCoarseIncrement();
case 7:
return scale.getFineIncrement();
case 7:
case 8:
return scale.getMin();
case 8:
case 9:
return scale.getMax();
default:
return null;
@ -73,12 +75,12 @@ public final class ScalesTableModel extends DefaultTableModel {
return null;
}
}
@Override
public final int getRowCount() {
return (null != scales) ? scales.size() : 0;
}
@Override
public final Class<? extends Object> getColumnClass(int column) {
return getValueAt(0, column).getClass();
@ -88,7 +90,7 @@ public final class ScalesTableModel extends DefaultTableModel {
public final boolean isCellEditable(int row, int column) {
return false;
}
public final void setScalesList(Vector<Scale> scales) {
this.scales = scales;
}

View File

@ -233,12 +233,12 @@ public class TableToolBar extends JToolBar implements MouseListener, ItemListene
} catch (PropertyVetoException ex) {
}
frame.requestFocusInWindow();
try {
setValue(frame.getTable());
} catch (UserLevelException e1) {
e1.printStackTrace();
}
setValue(frame.getTable());
} catch (UserLevelException e1) {
e1.printStackTrace();
}
}
};
@ -312,47 +312,47 @@ public class TableToolBar extends JToolBar implements MouseListener, ItemListene
}
public void updateTableToolBar() {
Table t = getTable();
if(t != null)
this.updateTableToolBar(t);
Table t = getTable();
if(t != null)
this.updateTableToolBar(t);
}
private void saveFineCourseValuesInTable(Table t) {
if(t == null || t.getCurrentScale() == null) return;
double incCoarse = 0;
double incFine = 0;
try {
//Commit the value which was typed (if field still has focus)
incrementByCoarse.commitEdit();
incrementByFine.commitEdit();
incCoarse = Double.parseDouble(String.valueOf(incrementByCoarse.getValue()));
incFine = Double.parseDouble(String.valueOf(incrementByFine.getValue()));
}
//Current value in the inc/dec field are not valid
catch(ParseException e) {
return;
}
//Should not happen since ParseException would happen before that
catch(NumberFormatException e) {
return;
}
//Save current inc/dec values in table before we switch
if(incCoarse!=0 && incFine != 0) {
t.updateIncrementDecrementValues(incFine,incCoarse);
}
if(t == null || t.getCurrentScale() == null) return;
double incCoarse = 0;
double incFine = 0;
try {
//Commit the value which was typed (if field still has focus)
incrementByCoarse.commitEdit();
incrementByFine.commitEdit();
incCoarse = Double.parseDouble(String.valueOf(incrementByCoarse.getValue()));
incFine = Double.parseDouble(String.valueOf(incrementByFine.getValue()));
}
//Current value in the inc/dec field are not valid
catch(ParseException e) {
return;
}
//Should not happen since ParseException would happen before that
catch(NumberFormatException e) {
return;
}
//Save current inc/dec values in table before we switch
if(incCoarse!=0 && incFine != 0) {
t.updateIncrementDecrementValues(incFine,incCoarse);
}
}
public void updateTableToolBar(Table selectedTable) {
//Select the parent Table always instead?
//if(selectedTable instanceof Table1D)selectedTable = ((Table1D)selectedTable).getAxisParent();
//Select the parent Table always instead?
//if(selectedTable instanceof Table1D)selectedTable = ((Table1D)selectedTable).getAxisParent();
if(selectedTable == null && this.selectedTable == null) {
// Skip if the table is the same to avoid multiple updates
return;
@ -365,7 +365,7 @@ public class TableToolBar extends JToolBar implements MouseListener, ItemListene
//Save the current inc/dec values in the table
saveFineCourseValuesInTable(this.selectedTable);
saveFineCourseValuesInTable(this.selectedTable);
this.selectedTable = selectedTable;
setBorder(toolbarBorder);
@ -388,7 +388,7 @@ public class TableToolBar extends JToolBar implements MouseListener, ItemListene
{
this.scaleSelection.setSelectedItem("Default");
} else {
this.scaleSelection.setSelectedItem(selectedTable.getCurrentScale().getName());
this.scaleSelection.setSelectedItem(selectedTable.getCurrentScale().getCategory());
}
toggleTableToolBar(selectedTable);
@ -513,7 +513,7 @@ public class TableToolBar extends JToolBar implements MouseListener, ItemListene
scaleSelection.removeAllItems();
for (Scale scale : scales) {
scaleSelection.addItem(scale.getName());
scaleSelection.addItem(scale.getCategory());
}
// and put it back
@ -528,28 +528,28 @@ public class TableToolBar extends JToolBar implements MouseListener, ItemListene
return;
}
try {
if (e.getSource() == incrementCoarse) {
incrementCoarse(curTable);
} else if (e.getSource() == decrementCoarse) {
decrementCoarse(curTable);
} else if (e.getSource() == enable3d) {
enable3d(curTable);
} else if (e.getSource() == incrementFine) {
incrementFine(curTable);
} else if (e.getSource() == decrementFine) {
decrementFine(curTable);
} else if (e.getSource() == multiply) {
multiply(curTable);
} else if (e.getSource() == setValue) {
setValue(curTable);
} else if (e.getSource() == colorCells) {
colorCells(curTable);
} else if (e.getSource() == refreshCompare) {
refreshCompare(curTable);
}
if (e.getSource() == incrementCoarse) {
incrementCoarse(curTable);
} else if (e.getSource() == decrementCoarse) {
decrementCoarse(curTable);
} else if (e.getSource() == enable3d) {
enable3d(curTable);
} else if (e.getSource() == incrementFine) {
incrementFine(curTable);
} else if (e.getSource() == decrementFine) {
decrementFine(curTable);
} else if (e.getSource() == multiply) {
multiply(curTable);
} else if (e.getSource() == setValue) {
setValue(curTable);
} else if (e.getSource() == colorCells) {
colorCells(curTable);
} else if (e.getSource() == refreshCompare) {
refreshCompare(curTable);
}
}
catch(UserLevelException ex) {
TableView.showInvalidUserLevelPopup(ex);
TableView.showInvalidUserLevelPopup(ex);
}
}
@ -771,7 +771,7 @@ public class TableToolBar extends JToolBar implements MouseListener, ItemListene
if (e.getSource() == scaleSelection) {
// scale changed
try {
curTable.setScaleByName((String)scaleSelection.getSelectedItem());
curTable.setScaleByCategory((String)scaleSelection.getSelectedItem());
updateToolbarIncrementDecrementValues();
} catch (NameNotFoundException e1) {
e1.printStackTrace();
@ -818,10 +818,10 @@ public class TableToolBar extends JToolBar implements MouseListener, ItemListene
//Set the value
try {
table3d.setRealValue(String.valueOf(value));
} catch (UserLevelException e) {
e.printStackTrace();
}
table3d.setRealValue(String.valueOf(value));
} catch (UserLevelException e) {
e.printStackTrace();
}
}
}
@ -846,4 +846,4 @@ public class TableToolBar extends JToolBar implements MouseListener, ItemListene
public Table getSelectedTable() {
return this.selectedTable;
}
}
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2020 RomRaider.com
* Copyright (C) 2006-2021 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
@ -28,6 +28,7 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ResourceBundle;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
@ -38,6 +39,8 @@ import com.romraider.xml.DOMSettingsUnmarshaller;
import com.sun.org.apache.xerces.internal.parsers.DOMParser;
public class SettingsManager {
private static final Logger LOGGER =
Logger.getLogger(SettingsManager.class);
private static final ResourceBundle rb = new ResourceUtil().getBundle(
SettingsManager.class.getName());
private static final String SETTINGS_FILE = "/settings.xml";
@ -73,6 +76,7 @@ public class SettingsManager {
sf = new File(USER_HOME + SETTINGS_FILE);
settingsFileIn = new FileInputStream(sf);
}
LOGGER.info("Loaded settings from file: " + settingsDir.replace("\\", "/") + SETTINGS_FILE);
final InputSource src = new InputSource(settingsFileIn);
final DOMSettingsUnmarshaller domUms = new DOMSettingsUnmarshaller();

View File

@ -51,16 +51,16 @@ import com.romraider.util.SettingsManager;
public class TableScaleUnmarshaller {
private static final Logger LOGGER = Logger.getLogger(TableScaleUnmarshaller.class);
private final Map<String, Integer> tableNames = new HashMap<String, Integer>();
private final Map<String, Integer> tableNames = new HashMap<String, Integer>();
private final List<Scale> scales = new ArrayList<Scale>();
private String memModelEndian = null;
public void setMemModelEndian(String endian) {
memModelEndian = endian;
memModelEndian = endian;
}
public void unmarshallBaseScales(Node rootNode) {
NodeList nodes = rootNode.getChildNodes();
NodeList nodes = rootNode.getChildNodes();
Node n;
for (int i = 0; i < nodes.getLength(); i++) {
@ -68,336 +68,346 @@ public class TableScaleUnmarshaller {
if (n.getNodeType() == ELEMENT_NODE
&& n.getNodeName().equalsIgnoreCase("scalingbase")) {
scales.add(unmarshallScale(n, new Scale()));
unmarshallScale(n, new Scale());
}
}
}
public Table unmarshallTable(Node tableNode, Table table, Rom rom)
throws XMLParseException, TableIsOmittedException, Exception {
if (unmarshallAttribute(tableNode, "omit", "false").equalsIgnoreCase(
"true")) { // remove table if omitted
throw new TableIsOmittedException();
}
if (!unmarshallAttribute(tableNode, "base", "none").equalsIgnoreCase(
"none")) { // copy base table for inheritance
try {
table = (Table) ObjectCloner
.deepCopy(rom.getTableByName(unmarshallAttribute(tableNode,
"base", "none")));
public Table unmarshallTable(Node tableNode, Table table, Rom rom)
throws XMLParseException, TableIsOmittedException, Exception {
} catch (TableNotFoundException ex) { /* table not found, do nothing */
if (unmarshallAttribute(tableNode, "omit", "false").equalsIgnoreCase(
"true")) { // remove table if omitted
throw new TableIsOmittedException();
}
} catch (InvalidTableNameException ex) { // Table name is invalid, do nothing.
if (!unmarshallAttribute(tableNode, "base", "none").equalsIgnoreCase(
"none")) { // copy base table for inheritance
try {
table = (Table) ObjectCloner
.deepCopy(rom.getTableByName(unmarshallAttribute(tableNode,
"base", "none")));
} catch (NullPointerException ex) {
JOptionPane.showMessageDialog(ECUEditorManager.getECUEditor(),
new DebugPanel(ex, SettingsManager.getSettings().getSupportURL()), "Exception",
JOptionPane.ERROR_MESSAGE);
}
}
} catch (TableNotFoundException ex) { /* table not found, do nothing */
if (table == null) {
// create new instance (otherwise it
// is inherited)
final String tn = unmarshallAttribute(tableNode, "name", "unknown");
final String type = unmarshallAttribute(tableNode, "type", "none");
} catch (InvalidTableNameException ex) { // Table name is invalid, do nothing.
if (tableNames.containsKey(tn) || type.contains("xis")) {
if (type.equalsIgnoreCase("3D")) {
table = new Table3D();
} catch (NullPointerException ex) {
JOptionPane.showMessageDialog(ECUEditorManager.getECUEditor(),
new DebugPanel(ex, SettingsManager.getSettings().getSupportURL()), "Exception",
JOptionPane.ERROR_MESSAGE);
}
}
} else if (type.equalsIgnoreCase("2D")) {
table = new Table2D();
if (table == null) {
// create new instance (otherwise it is inherited)
final String tn = unmarshallAttribute(tableNode, "name", "unknown");
final String type = unmarshallAttribute(tableNode, "type", "none");
} else if (type.equalsIgnoreCase("1D")) {
table = new Table1D(Table.TableType.TABLE_1D);
if (tableNames.containsKey(tn) || type.contains("xis")) {
if (type.equalsIgnoreCase("3D")) {
table = new Table3D();
} else if (type.equalsIgnoreCase("X Axis")
|| type.equalsIgnoreCase("Static X Axis")) {
table = new Table1D(Table.TableType.X_AXIS);
} else if (type.equalsIgnoreCase("2D")) {
table = new Table2D();
} else if (type.equalsIgnoreCase("Y Axis")
|| type.equalsIgnoreCase("Static Y Axis")) {
table = new Table1D(Table.TableType.Y_AXIS);
} else if (type.equalsIgnoreCase("Switch")) {
table = new TableSwitch();
} else if (type.equalsIgnoreCase("1D")) {
table = new Table1D(Table.TableType.TABLE_1D);
} else if (type.equalsIgnoreCase("BitwiseSwitch")) {
table = new TableBitwiseSwitch();
}
else if(type.equalsIgnoreCase("none")){
throw new XMLParseException("Table type unspecified for "
+ tableNode.getAttributes().getNamedItem("name"));
}
else {
throw new XMLParseException("Table type " + type + " unknown for "
+ tableNode.getAttributes().getNamedItem("name"));
}
}
else {
return table;
}
}
} else if (type.equalsIgnoreCase("X Axis")
|| type.equalsIgnoreCase("Static X Axis")) {
table = new Table1D(Table.TableType.X_AXIS);
// unmarshall table attributes
final String tn = unmarshallAttribute(tableNode, "name", table.getName());
table.setName(tn);
if (unmarshallAttribute(tableNode, "beforeram", "false")
.equalsIgnoreCase("true")) {
table.setBeforeRam(true);
}
table.setDataLayout(unmarshallAttribute(tableNode, "dataLayout", ""));
table.setCategory(unmarshallAttribute(tableNode, "category",
table.getCategory()));
if (table.getStorageType() < 1) {
table.setSignedData(RomAttributeParser
.parseStorageDataSign(unmarshallAttribute(tableNode,
"storagetype",
String.valueOf(table.getStorageType()))));
}
table.setStorageType(RomAttributeParser
.parseStorageType(unmarshallAttribute(tableNode, "storagetype",
String.valueOf(table.getStorageType()))));
if (memModelEndian == null) {
table.setEndian(RomAttributeParser.parseEndian(unmarshallAttribute(
tableNode, "endian", table.getEndian().getMarshallingString())));
}
else {
final Settings.Endian endian = memModelEndian.equalsIgnoreCase("little") ? Settings.Endian.LITTLE : Settings.Endian.BIG;
table.setMemModelEndian(endian);
table.setEndian(endian);
}
if (tableNames.containsKey(tn)) {
table.setStorageAddress(tableNames.get(tn));
}
else {
table.setStorageAddress(RomAttributeParser
.parseHexString(unmarshallAttribute(tableNode,
"storageaddress",
String.valueOf(table.getStorageAddress()))));
}
table.setDescription(unmarshallAttribute(tableNode, "description",
table.getDescription()));
table.setDataSize(unmarshallAttribute(tableNode, "sizey",
unmarshallAttribute(tableNode, "sizex", table.getDataSize())));
table.setFlip(unmarshallAttribute(tableNode, "flipy",
unmarshallAttribute(tableNode, "flipx", table.getFlip())));
table.setUserLevel(unmarshallAttribute(tableNode, "userlevel",
table.getUserLevel()));
table.setLocked(unmarshallAttribute(tableNode, "locked",
table.isLocked()));
table.setLogParam(unmarshallAttribute(tableNode, "logparam",
table.getLogParam()));
table.setStringMask(
unmarshallAttribute(tableNode, "mask", "0"));
} else if (type.equalsIgnoreCase("Y Axis")
|| type.equalsIgnoreCase("Static Y Axis")) {
table = new Table1D(Table.TableType.Y_AXIS);
} else if (type.equalsIgnoreCase("Switch")) {
table = new TableSwitch();
if (table.getType() == Table.TableType.TABLE_3D) {
((Table3D) table).setSwapXY(unmarshallAttribute(tableNode,
"swapxy", ((Table3D) table).getSwapXY()));
((Table3D) table).setFlipX(unmarshallAttribute(tableNode, "flipx",
((Table3D) table).getFlipX()));
((Table3D) table).setFlipY(unmarshallAttribute(tableNode, "flipy",
((Table3D) table).getFlipY()));
((Table3D) table).setSizeX(unmarshallAttribute(tableNode, "sizex",
((Table3D) table).getSizeX()));
((Table3D) table).setSizeY(unmarshallAttribute(tableNode, "sizey",
((Table3D) table).getSizeY()));
}
Node n;
NodeList nodes = tableNode.getChildNodes();
} else if (type.equalsIgnoreCase("BitwiseSwitch")) {
table = new TableBitwiseSwitch();
}
else if(type.equalsIgnoreCase("none")){
throw new XMLParseException("Table type unspecified for "
+ tableNode.getAttributes().getNamedItem("name"));
}
else {
throw new XMLParseException("Table type " + type + " unknown for "
+ tableNode.getAttributes().getNamedItem("name"));
}
}
else {
return table;
}
}
for (int i = 0; i < nodes.getLength(); i++) {
n = nodes.item(i);
// unmarshall table attributes
final String tn = unmarshallAttribute(tableNode, "name", table.getName());
table.setName(tn);
if (unmarshallAttribute(tableNode, "beforeram", "false")
.equalsIgnoreCase("true")) {
table.setBeforeRam(true);
}
if (n.getNodeType() == ELEMENT_NODE) {
if (n.getNodeName().equalsIgnoreCase("table")) {
table.setDataLayout(unmarshallAttribute(tableNode, "dataLayout", ""));
table.setCategory(unmarshallAttribute(tableNode, "category",
table.getCategory()));
if (table.getStorageType() < 1) {
table.setSignedData(RomAttributeParser
.parseStorageDataSign(unmarshallAttribute(tableNode,
"storagetype",
String.valueOf(table.getStorageType()))));
}
table.setStorageType(RomAttributeParser
.parseStorageType(unmarshallAttribute(tableNode, "storagetype",
String.valueOf(table.getStorageType()))));
if (memModelEndian == null) {
table.setEndian(RomAttributeParser.parseEndian(unmarshallAttribute(
tableNode, "endian", table.getEndian().getMarshallingString())));
}
else {
final Settings.Endian endian = memModelEndian.equalsIgnoreCase("little") ? Settings.Endian.LITTLE : Settings.Endian.BIG;
table.setMemModelEndian(endian);
table.setEndian(endian);
}
if (tableNames.containsKey(tn)) {
table.setStorageAddress(tableNames.get(tn));
}
else {
table.setStorageAddress(RomAttributeParser
.parseHexString(unmarshallAttribute(tableNode,
"storageaddress",
String.valueOf(table.getStorageAddress()))));
}
if (table.getType() == Table.TableType.TABLE_2D) { // if table is 2D,
// parse axis
table.setDescription(unmarshallAttribute(tableNode, "description",
table.getDescription()));
table.setDataSize(unmarshallAttribute(tableNode, "sizey",
unmarshallAttribute(tableNode, "sizex", table.getDataSize())));
table.setFlip(unmarshallAttribute(tableNode, "flipy",
unmarshallAttribute(tableNode, "flipx", table.getFlip())));
table.setUserLevel(unmarshallAttribute(tableNode, "userlevel",
table.getUserLevel()));
table.setLocked(unmarshallAttribute(tableNode, "locked",
table.isLocked()));
table.setLogParam(unmarshallAttribute(tableNode, "logparam",
table.getLogParam()));
table.setStringMask(
unmarshallAttribute(tableNode, "mask", "0"));
if (RomAttributeParser
.parseTableType(unmarshallAttribute(n, "type",
"unknown")) == Table.TableType.Y_AXIS
|| RomAttributeParser
.parseTableType(unmarshallAttribute(n,
"type", "unknown")) == Table.TableType.X_AXIS) {
if (table.getType() == Table.TableType.TABLE_3D) {
((Table3D) table).setSwapXY(unmarshallAttribute(tableNode,
"swapxy", ((Table3D) table).getSwapXY()));
((Table3D) table).setFlipX(unmarshallAttribute(tableNode, "flipx",
((Table3D) table).getFlipX()));
((Table3D) table).setFlipY(unmarshallAttribute(tableNode, "flipy",
((Table3D) table).getFlipY()));
((Table3D) table).setSizeX(unmarshallAttribute(tableNode, "sizex",
((Table3D) table).getSizeX()));
((Table3D) table).setSizeY(unmarshallAttribute(tableNode, "sizey",
((Table3D) table).getSizeY()));
}
Table1D tempTable = (Table1D) unmarshallTable(n,
((Table2D) table).getAxis(), rom);
if (tempTable.getDataSize() != table.getDataSize()) {
tempTable.setDataSize(table.getDataSize());
}
tempTable.setData(((Table2D) table).getAxis().getData());
((Table2D) table).setAxis(tempTable);
Node n;
NodeList nodes = tableNode.getChildNodes();
}
} else if (table.getType() == Table.TableType.TABLE_3D) { // if table
// is 3D,
// populate
// xAxis
if (RomAttributeParser
.parseTableType(unmarshallAttribute(n, "type",
"unknown")) == Table.TableType.X_AXIS) {
for (int i = 0; i < nodes.getLength(); i++) {
n = nodes.item(i);
Table1D tempTable = (Table1D) unmarshallTable(n,
((Table3D) table).getXAxis(), rom);
if (tempTable.getDataSize() != ((Table3D) table)
.getSizeX()) {
tempTable.setDataSize(((Table3D) table)
.getSizeX());
}
tempTable.setData(((Table3D) table).getXAxis().getData());
((Table3D) table).setXAxis(tempTable);
if (n.getNodeType() == ELEMENT_NODE) {
if (n.getNodeName().equalsIgnoreCase("table")) {
} else if (RomAttributeParser
.parseTableType(unmarshallAttribute(n, "type",
"unknown")) == Table.TableType.Y_AXIS) {
if (table.getType() == Table.TableType.TABLE_2D) { // if table is 2D,
// parse axis
if (RomAttributeParser
.parseTableType(unmarshallAttribute(n, "type",
"unknown")) == Table.TableType.Y_AXIS
|| RomAttributeParser
.parseTableType(unmarshallAttribute(n,
"type", "unknown")) == Table.TableType.X_AXIS) {
Table1D tempTable = (Table1D) unmarshallTable(n,
((Table3D) table).getYAxis(), rom);
if (tempTable.getDataSize() != ((Table3D) table)
.getSizeY()) {
tempTable.setDataSize(((Table3D) table)
.getSizeY());
}
tempTable.setData(((Table3D) table).getYAxis().getData());
((Table3D) table).setYAxis(tempTable);
}
}
Table1D tempTable = (Table1D) unmarshallTable(n,
((Table2D) table).getAxis(), rom);
if (tempTable.getDataSize() != table.getDataSize()) {
tempTable.setDataSize(table.getDataSize());
}
tempTable.setData(((Table2D) table).getAxis().getData());
((Table2D) table).setAxis(tempTable);
}
} else if (n.getNodeName().equalsIgnoreCase("scaling")) {
// check whether scale already exists. if so, modify, else
// use new instance
Scale baseScale = table.getScale(unmarshallAttribute(n,"name", "Default"));
table.addScale(unmarshallScale(n, baseScale));
} else if (table.getType() == Table.TableType.TABLE_3D) { // if table
// is 3D,
// populate
// xAxis
if (RomAttributeParser
.parseTableType(unmarshallAttribute(n, "type",
"unknown")) == Table.TableType.X_AXIS) {
} else if (n.getNodeName().equalsIgnoreCase("data")) {
// parse and add data to table
if(table instanceof Table1D) {
((Table1D)table).addStaticDataCell(unmarshallText(n));
} else {
// Why would this happen. Static should only be for axis.
LOGGER.error("Error adding static data cell.");
}
Table1D tempTable = (Table1D) unmarshallTable(n,
((Table3D) table).getXAxis(), rom);
if (tempTable.getDataSize() != ((Table3D) table)
.getSizeX()) {
tempTable.setDataSize(((Table3D) table)
.getSizeX());
}
tempTable.setData(((Table3D) table).getXAxis().getData());
((Table3D) table).setXAxis(tempTable);
} else if (n.getNodeName().equalsIgnoreCase("description")) {
table.setDescription(unmarshallText(n));
} else if (RomAttributeParser
.parseTableType(unmarshallAttribute(n, "type",
"unknown")) == Table.TableType.Y_AXIS) {
} else if (n.getNodeName().equalsIgnoreCase("state")) {
table.setValues(
unmarshallAttribute(n, "name", ""),
unmarshallAttribute(n, "data", "0"));
} else if (n.getNodeName().equalsIgnoreCase("bit")) {
table.setValues(
unmarshallAttribute(n, "name", ""),
unmarshallAttribute(n, "position", "0"));
} else { /* unexpected element in Table (skip) */
}
} else { /* unexpected node-type in Table (skip) */
}
}
return table;
}
/**
* Create a list of table names to be used as a filter on the inherited
* tables to reduce unnecessary table object creation.
* @param nodes - the NodeList to filter
* @throws XMLParseException
* @throws TableIsOmittedException
* @throws Exception
*/
public void filterFoundRomTables (NodeList nodes) {
Node n;
Table1D tempTable = (Table1D) unmarshallTable(n,
((Table3D) table).getYAxis(), rom);
if (tempTable.getDataSize() != ((Table3D) table)
.getSizeY()) {
tempTable.setDataSize(((Table3D) table)
.getSizeY());
}
tempTable.setData(((Table3D) table).getYAxis().getData());
((Table3D) table).setYAxis(tempTable);
}
}
for (int i = 0; i < nodes.getLength(); i++) {
n = nodes.item(i);
if (n.getNodeType() == ELEMENT_NODE
&& n.getNodeName().equalsIgnoreCase("table")) {
} else if (n.getNodeName().equalsIgnoreCase("scaling")) {
// check whether scale already exists. if so, modify, else
// use new instance
Scale baseScale = table.getScale(unmarshallAttribute(n, "category", "Default"));
table.addScale(unmarshallScale(n, baseScale));
final String name = unmarshallAttribute(n, "name", "unknown");
final int address = RomAttributeParser
.parseHexString(unmarshallAttribute(n,
"storageaddress", "-1"));
} else if (n.getNodeName().equalsIgnoreCase("data")) {
// parse and add data to table
if(table instanceof Table1D) {
((Table1D)table).addStaticDataCell(unmarshallText(n));
} else {
// Why would this happen. Static should only be for axis.
LOGGER.error("Error adding static data cell.");
}
if (unmarshallAttribute(n, "omit", "false").equalsIgnoreCase(
"true")) {
return;
}
} else if (n.getNodeName().equalsIgnoreCase("description")) {
table.setDescription(unmarshallText(n));
if (!tableNames.containsKey(name) && address >= 0) {
tableNames.put(name, address);
}
else if (tableNames.containsKey(name)) {
if (tableNames.get(name) < 1 && address >= 0) {
tableNames.put(name, address);
}
}
}
}
}
public Scale unmarshallScale(Node scaleNode, Scale scale) {
} else if (n.getNodeName().equalsIgnoreCase("state")) {
table.setValues(
unmarshallAttribute(n, "name", ""),
unmarshallAttribute(n, "data", "0"));
} else if (n.getNodeName().equalsIgnoreCase("bit")) {
table.setValues(
unmarshallAttribute(n, "name", ""),
unmarshallAttribute(n, "position", "0"));
// look for base scale first
String base = unmarshallAttribute(scaleNode, "base", "none");
if (!base.equalsIgnoreCase("none")) {
for (Scale scaleItem : scales) {
} else { /* unexpected element in Table (skip) */
}
} else { /* unexpected node-type in Table (skip) */
}
}
return table;
}
// check whether name matches base and set scale if so
if (scaleItem.getName().equalsIgnoreCase(base)) {
try {
scale = (Scale) ObjectCloner.deepCopy(scaleItem);
/**
* Create a list of table names to be used as a filter on the inherited
* tables to reduce unnecessary table object creation.
* @param nodes - the NodeList to filter
* @throws XMLParseException
* @throws TableIsOmittedException
* @throws Exception
*/
public void filterFoundRomTables (NodeList nodes) {
Node n;
} catch (Exception ex) {
JOptionPane.showMessageDialog(
ECUEditorManager.getECUEditor(),
new DebugPanel(ex, SettingsManager.getSettings()
.getSupportURL()), "Exception",
JOptionPane.ERROR_MESSAGE);
}
}
}
}
//Name should always be set to Default even if missing
scale.setName(unmarshallAttribute(scaleNode, "name", "Default"));
//Iterate over available attributes
for(int i=0; i < scaleNode.getAttributes().getLength(); i++) {
Node attr = scaleNode.getAttributes().item(i);
String name = attr.getNodeName();
String value = attr.getNodeValue();
if(name.equalsIgnoreCase("units"))scale.setUnit(value);
else if(name.equalsIgnoreCase("expression")) scale.setExpression(value);
else if(name.equalsIgnoreCase("to_byte")) scale.setByteExpression(value);
else if(name.equalsIgnoreCase("format")) scale.setFormat(value);
else if(name.equalsIgnoreCase("max")) scale.setMax(Double.parseDouble(value));
else if(name.equalsIgnoreCase("min")) scale.setMin(Double.parseDouble(value));
else if(name.equalsIgnoreCase("coarseincrement") || name.equalsIgnoreCase("increment"))
scale.setCoarseIncrement(Double.parseDouble(value));
else if(name.equalsIgnoreCase("fineincrement")) scale.setFineIncrement(Double.parseDouble(value));
}
for (Scale s : scales) {
if (s.equals(scale)) {
return s;
}
}
scales.add(scale);
return scale;
}
for (int i = 0; i < nodes.getLength(); i++) {
n = nodes.item(i);
if (n.getNodeType() == ELEMENT_NODE
&& n.getNodeName().equalsIgnoreCase("table")) {
final String name = unmarshallAttribute(n, "name", "unknown");
final int address = RomAttributeParser
.parseHexString(unmarshallAttribute(n,
"storageaddress", "-1"));
if (unmarshallAttribute(n, "omit", "false").equalsIgnoreCase(
"true")) {
return;
}
if (!tableNames.containsKey(name) && address >= 0) {
tableNames.put(name, address);
}
else if (tableNames.containsKey(name)) {
if (tableNames.get(name) < 1 && address >= 0) {
tableNames.put(name, address);
}
}
}
}
}
public Scale unmarshallScale(Node scaleNode, Scale scale) {
// look for base scaling attribute first
String base = unmarshallAttribute(scaleNode, "base", "none");
if (!base.equalsIgnoreCase("none")) {
// check whether base value matches the name of a an existing
// scalingbase, if so, inherit from scalingbase
for (Scale scaleItem : scales) {
if (scaleItem.getName().equalsIgnoreCase(base)) {
try {
scale = (Scale) ObjectCloner.deepCopy(scaleItem);
} catch (Exception ex) {
JOptionPane.showMessageDialog(
ECUEditorManager.getECUEditor(),
new DebugPanel(ex, SettingsManager.getSettings()
.getSupportURL()), "Exception",
JOptionPane.ERROR_MESSAGE);
}
}
}
}
// Set Category to Default if missing or not inherited from scalingbase
if (base.equalsIgnoreCase("none")) {
scale.setCategory(unmarshallAttribute(scaleNode, "category", "Default"));
}
// Set scaling name, if a scaling has no name attribute (scaling is
// defined in a table element), try and use the units value as its
// name, otherwise use none
if (!scale.getCategory().equalsIgnoreCase("Raw Value") &&
scale.getName().equalsIgnoreCase("Raw Value")) {
scale.setName(unmarshallAttribute(scaleNode, "name",
unmarshallAttribute(scaleNode, "units", "none")));
}
// Iterate over other available attributes
for(int i=0; i < scaleNode.getAttributes().getLength(); i++) {
Node attr = scaleNode.getAttributes().item(i);
String name = attr.getNodeName();
String value = attr.getNodeValue();
if(name.equalsIgnoreCase("units"))scale.setUnit(value);
else if(name.equalsIgnoreCase("expression")) scale.setExpression(value);
else if(name.equalsIgnoreCase("to_byte")) scale.setByteExpression(value);
else if(name.equalsIgnoreCase("format")) scale.setFormat(value);
else if(name.equalsIgnoreCase("max")) scale.setMax(Double.parseDouble(value));
else if(name.equalsIgnoreCase("min")) scale.setMin(Double.parseDouble(value));
else if(name.equalsIgnoreCase("coarseincrement") || name.equalsIgnoreCase("increment"))
scale.setCoarseIncrement(Double.parseDouble(value));
else if(name.equalsIgnoreCase("fineincrement")) scale.setFineIncrement(Double.parseDouble(value));
}
for (Scale s : scales) {
if (s.equals(scale)) {
return s;
}
}
scales.add(scale);
return scale;
}
// for unit testing
public List<Scale> getScales() {
return scales;
}
}

View File

@ -0,0 +1,68 @@
<roms>
<rom>
<romid>
<xmlid>32BITBASE</xmlid>
<market>USDM</market>
<make>Subaru</make>
<model>Impreza</model>
<submodel>STi</submodel>
<transmission>MT</transmission>
<filesize>512kb</filesize>
<memmodel>SH7055</memmodel>
<flashmethod>sti04</flashmethod>
</romid>
<table type="2D" name="A/F Learning #1 Airflow Ranges" category="Fueling - AF Correction / Learning" storagetype="float" endian="little" sizey="3" userlevel="4">
<scaling units="Mass Airflow (g/s)" expression="x" to_byte="x" format="0.00" fineincrement=".1" coarseincrement="1" />
<table type="Static Y Axis" name="A/F Learning Store/Apply Ranges" sizey="3">
<data> Max Range A / Min Range B </data>
<data> Max Range B / Min Range C </data>
<data> Max Range C / Min Range D </data>
</table>
<description>These are the airflow ranges in which the different long-term fuel trims are calculated in closed loop and applied to the same airflow ranges for both closed loop and open loop.</description>
</table>
<table type="2D" name="A/F Learning Airflow Ranges" category="Fueling - AF Correction / Learning" storagetype="float" endian="little" sizey="3" userlevel="4">
<scaling units="Mass Airflow (g/s)" expression="x" to_byte="x" format="0.00" fineincrement=".1" coarseincrement="1" />
<table type="Static Y Axis" name="A/F Learning #1 and #2 Store/Apply Ranges" sizey="3">
<data> Max Range A / Min Range B </data>
<data> Max Range B / Min Range C </data>
<data> Max Range C / Min Range D </data>
</table>
<description>These are the airflow ranges in which the different long-term fuel trims are calculated in closed loop and applied to the same airflow ranges for both closed loop and open loop.</description>
</table>
</rom>
<rom base="32BITBASE">
<romid>
<xmlid>A2WC510N</xmlid>
<internalidaddress>2000</internalidaddress>
<internalidstring>A2WC510N</internalidstring>
<ecuid>2F12785206</ecuid>
<year>05</year>
<market>USDM</market>
<make>Subaru</make>
<model>Legacy</model>
<submodel>GT</submodel>
<transmission>MT</transmission>
<memmodel>SH7058</memmodel>
<flashmethod>sti05</flashmethod>
<filesize>1024kb</filesize>
</romid>
<table name="A/F Learning #1 Airflow Ranges" storageaddress="0xC7078" />
</rom>
<rom base="A2WC510N">
<romid>
<xmlid>A2WC510S</xmlid>
<internalidaddress>2000</internalidaddress>
<internalidstring>A2WC510S</internalidstring>
<ecuid>2F12795206</ecuid>
<year>05</year>
<market>USDM</market>
<make>Subaru</make>
<model>Outback</model>
<submodel>XT</submodel>
<transmission>MT</transmission>
<memmodel>SH7058</memmodel>
<flashmethod>sti05</flashmethod>
<filesize>1024kb</filesize>
</romid>
</rom>
</roms>

View File

@ -0,0 +1,87 @@
<!-- demonstrate scalingbase use and <table base= inheritance -->
<roms>
<scalingbase category="Standard" name="BoostTarget_psirelativesealevel" units="Boost Target (psi relative sea level)" expression="(x-760)*.01933677" to_byte="(x/.01933677)+760" format="0.00" fineincrement=".01" coarseincrement=".5" />
<scalingbase name="rpm" units="RPM" expression="x" to_byte="x" format="#" fineincrement="50" coarseincrement="100" />
<scalingbase name="targetboostcomppercent" expression="(x*.78125)-100" to_byte="(x+100)/.78125" format="0.0" fineincrement=".4" coarseincrement="1" />
<scalingbase name="WastegateDutyCycle_%" units="Wastegate Duty Cycle (%)" expression="x*.00390625" to_byte="x/.00390625" format="0.0" fineincrement=".2" coarseincrement="1" min="0.1" max="99.9"/>
<scalingbase category="Metric" name="BoostTarget_barabsolute" units="Boost Target (bar absolute)" expression="x*.001333224" to_byte="x/.001333224" format="#0.000" fineincrement=".01" coarseincrement=".1" />
<rom>
<romid>
<xmlid>32BITBASE</xmlid>
<market>USDM</market>
<make>Subaru</make>
<model>Impreza</model>
<submodel>STi</submodel>
<transmission>MT</transmission>
<filesize>512kb</filesize>
<memmodel>SH7055</memmodel>
<flashmethod>sti04</flashmethod>
</romid>
<table type="3D" name="Target Boost A" category="Boost Control - Target" storagetype="uint16" endian="big" sizex="8" sizey="12" userlevel="1" logparam="E52">
<scaling base="BoostTarget_barabsolute"/>
<scaling base="BoostTarget_psirelativesealevel"/>
<table type="X Axis" name="Throttle Plate Opening Angle" storagetype="float" endian="little" logparam="E38">
<scaling units="%" expression="x/.84" to_byte="x*.84" format="0.0" fineincrement=".3" coarseincrement="1" />
</table>
<table type="Y Axis" name="Engine Speed" storagetype="float" endian="little" logparam="P8">
<scaling base="rpm"/>
</table>
<description>This map contains the desired boost targets. Boost compensation tables can impact the final boost target.</description>
</table>
<table base="Target Boost A" name="Target Boost B">
<description>Inherited Target Boost A</description>
</table>
<table type="3D" name="Initial Wastegate Duty A" category="Boost Control - Wastegate" storagetype="uint16" endian="big" sizex="8" sizey="12" userlevel="1" logparam="P36">
<scaling base="WastegateDutyCycle_%" />
<table type="X Axis" name="Throttle Plate Opening Angle" storagetype="float" endian="little" logparam="E38">
<scaling units="%" expression="x/.84" to_byte="x*.84" format="0.0" fineincrement=".3" coarseincrement="1" />
</table>
<table type="Y Axis" name="Engine Speed" storagetype="float" endian="little" logparam="P8">
<scaling base="rpm"/>
</table>
<description>These are the starting values for wastegate duty. Wastegate compensation tables are applied to initial and max wastegate duty values.</description>
</table>
<table type="3D" name="CL Fueling Target Compensation A (ECT)" category="Fueling - Closed Loop" storagetype="uint16" endian="big" sizex="16" sizey="3" userlevel="4">
<scaling units="Estimated Air/Fuel Ratio Points (Additive)" expression="(-x*.000224304213)+7.350001" to_byte="(x-7.350001)/-.000224304213" format="0.000" fineincrement=".01" coarseincrement=".1" />
<table type="X Axis" name="Coolant Temperature" storagetype="float" endian="little" logparam="P2">
<scaling category="Metric" units="Degrees C" expression="x" to_byte="x" format="#" fineincrement="1" coarseincrement="5" />
<scaling category="Standard" units="Degrees F" expression="(x*1.8)+32" to_byte="(x-32)/1.8" format="#" fineincrement="1" coarseincrement="5" />
</table>
<table type="Y Axis" name="Engine Load" storagetype="float" endian="little" logparam="E32">
<scaling units="g/rev" expression="x" to_byte="x" format="0.00" fineincrement=".01" coarseincrement=".1" />
</table>
<description>This is the compensation to the closed loop base fueling target based on coolant temp. Other compensations (some undefined), are also applied.</description>
</table>
</rom>
<rom base="32BITBASE">
<romid>
<xmlid>A2WC522S</xmlid>
<internalidaddress>2000</internalidaddress>
<internalidstring>A2WC522S</internalidstring>
<ecuid>2F12795606</ecuid>
<year>05</year>
<market>USDM</market>
<make>Subaru</make>
<model>Outback</model>
<submodel>XT</submodel>
<transmission>MT</transmission>
<memmodel>SH7058</memmodel>
<flashmethod>sti05</flashmethod>
<filesize>1024kb</filesize>
</romid>
<table name="Target Boost A" storageaddress="0xC11D4">
<table type="X Axis" storageaddress="0xC1184" />
<table type="Y Axis" storageaddress="0xC11A4" />
</table>
<table name="Target Boost B" storageaddress="0xC12E4">
<table type="X Axis" storageaddress="0xC1294" />
<table type="Y Axis" storageaddress="0xC12B4" />
</table>
<table name="Initial Wastegate Duty A" storageaddress="0xC0BC0" sizey="11">
<table type="X Axis" storageaddress="0xC0B74" />
<table type="Y Axis" storageaddress="0xC0B94" />
</table>
</rom>
</roms>

View File

@ -0,0 +1,113 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2021 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.EcuDefinitionInheritance;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import com.romraider.logger.ecu.comms.learning.tableaxis.SSMTableAxisQueryParameterSet;
import com.romraider.logger.ecu.comms.query.EcuQuery;
import com.romraider.logger.ecu.definition.EcuDefinition;
import com.romraider.logger.ecu.definition.EcuDefinitionImpl;
import com.romraider.logger.ecu.definition.xml.EcuDefinitionDocumentLoader;
import com.romraider.logger.ecu.definition.xml.EcuDefinitionInheritanceList;
import com.romraider.logger.ecu.definition.xml.EcuTableDefinitionHandler;
public class EcuDefinitionInheritanceTest {
/** Test the address manipulation needed to convert the def table
* address to the linear RAM read address.
*/
@Test
public void testAddress() {
List<String> AF_TABLE_NAMES = Arrays.asList(
"A/F Learning #1 Airflow Ranges",
"A/F Learning #1 Airflow Ranges ",
"A/F Learning Airflow Ranges");
Collection<EcuQuery> queries = new ArrayList<EcuQuery>();
EcuDefinition ecuDef = new EcuDefinitionImpl("2F12795206", "A2WC510S",
"05 outback xt", "A2WC510N", new File("src/test/definitions/LearningAirflowRanges.xml"));
Document document = EcuDefinitionDocumentLoader.getDocument(ecuDef);
queries = getTableAxisRanges(document, ecuDef, AF_TABLE_NAMES);
assertEquals(3, queries.size());
for (EcuQuery query : queries) {
System.out.println(query);
}
}
/**
* 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;
}
/**
* 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 = SSMTableAxisQueryParameterSet.build(
tableMap.get("storageaddress"),
tableMap.get("storagetype"),
tableMap.get("expression"),
tableMap.get("units"),
tableMap.get("sizey")
);
}
return tableAxisQuery;
}
}

View File

@ -0,0 +1,84 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2021 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.maps.checksum;
import static org.junit.Assert.assertEquals;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.junit.Test;
import com.romraider.util.HexUtil;
public class NcsCoDecTest {
final NcsCoDec codec = new NcsCoDec();
final String text = "FFFF22E4000115F8000116A000011724000117C80002B9C4E00180F884F820088B1B62F0E7EC9625D91426209623656062637205645C60430274901D7501655C029C760560530624D20D420B75019013D60C029C9011A0040624E4AC644CB18BE5127F204F266EF66DF66CF66BF66AF6000B69F697B481050848035EFFFF22E4";
final byte[] bin = HexUtil.asBytes(text);
final int scode = 0xC2C0823F;
final ByteBuffer data = ByteBuffer.allocate(bin.length).order(ByteOrder.BIG_ENDIAN).put(bin);
final String encoded = "118283C9B4953B9B63A23EE3EE224177089344AB4C466E96F606B2997EDEE9129E7B377498905B95D0C75576E88B5EBCBB0065BB03DFCB5279839C252FADBD8A8C1119449FBD8C25107BC5FB5961EB1E7FA50CC2A0BF7DC5B2414339FD0B213B321AAC721891B7AB6F0A837B0D088F7B185ADF86263BC56DBAB2D6D0118283C9";
@Test
public final void testEncodeData() {
final byte[] dataEncoded = codec.nisEncode(data, scode);
assertEquals(encoded, HexUtil.asHex(dataEncoded));
}
@Test
public final void testEncodedDataCrc() {
final byte[] dataEncoded = codec.nisEncode(data, scode);
assertEquals((short) 0xD10D, (short) codec.calcCrc(dataEncoded));
}
@Test
public final void testBitwiseComplementCrc() {
final byte[] dataEncoded = codec.nisEncode(data, scode);
assertEquals((short) 0x2EF2, (short) ~codec.calcCrc(dataEncoded));
}
@Test
public final void testBitwiseComplementCrcLitteEndian() {
final byte[] dataEncoded = codec.nisEncode(data, scode);
short bcCrc = (short) ~codec.calcCrc(dataEncoded);
short le = (short) (((bcCrc << 8) | ((bcCrc & 0xffff) >>> 8)) & 0xffff);
assertEquals((short) 0xF22E, le);
}
@Test
public final void testResidue() {
final byte[] dataEncoded = codec.nisEncode(data, scode);
short bcCrc = (short) ~codec.calcCrc(dataEncoded);
final byte[] crcCheck = new byte[dataEncoded.length + 2];
System.arraycopy(dataEncoded, 0, crcCheck, 0, dataEncoded.length);
crcCheck[crcCheck.length - 2] = (byte) (bcCrc & 0xff);
crcCheck[crcCheck.length - 1] = (byte) ((bcCrc & 0xffff) >>> 8);
assertEquals((short) 0xF0B8, (short) codec.calcCrc(crcCheck));
}
@Test
public final void testDecodeData() {
final byte[] dataEncoded = codec.nisEncode(data, scode);
final ByteBuffer bb = ByteBuffer.allocate(dataEncoded.length)
.order(ByteOrder.BIG_ENDIAN).put(dataEncoded);
final byte[] data = codec.nisDecode(bb, scode);
assertEquals(text, HexUtil.asHex(data));
}
}

View File

@ -0,0 +1,125 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2021 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.xml;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.w3c.dom.Document;
import com.romraider.logger.ecu.definition.EcuDefinition;
import com.romraider.logger.ecu.definition.EcuDefinitionImpl;
import com.romraider.logger.ecu.definition.xml.EcuDefinitionDocumentLoader;
import com.romraider.maps.Scale;
public class TableScaleUnmarshallerTest {
private final Document document = getDocument();
private final TableScaleUnmarshaller tableScaleHandler = new TableScaleUnmarshaller();
/** Test creation of scales from XML definition file scalingbase.
*/
@Test
public void testScalingBase() {
final List<Scale> expectedScales = buildExpectedScales();
tableScaleHandler.unmarshallBaseScales(document.getDocumentElement());
final List<Scale> scales = tableScaleHandler.getScales();
for (final Scale scale : scales) {
System.out.println(scale);
}
assertEquals(expectedScales.size(), scales.size());
for (Scale expectedScale : expectedScales) {
assertEquals(true, scales.contains(expectedScale));
}
}
private Document getDocument() {
final EcuDefinition ecuDef = new EcuDefinitionImpl("2F12795606", "A2WC522S",
"05 Outback XT", "32BITBASE", new File("src/test/definitions/scalingbase_test.xml"));
final Document document = EcuDefinitionDocumentLoader.getDocument(ecuDef);
return document;
}
private List<Scale> buildExpectedScales() {
final List<Scale> expectedScales = new ArrayList<Scale>();
final Scale BoostTarget_barabsolute = new Scale();
BoostTarget_barabsolute.setCategory("Metric");
BoostTarget_barabsolute.setName("BoostTarget_barabsolute");
BoostTarget_barabsolute.setExpression("x*.001333224");
BoostTarget_barabsolute.setByteExpression("x/.001333224");
BoostTarget_barabsolute.setUnit("Boost Target (bar absolute)");
BoostTarget_barabsolute.setFormat("#0.000");
BoostTarget_barabsolute.setCoarseIncrement(0.1);
BoostTarget_barabsolute.setFineIncrement(0.01);
expectedScales.add(BoostTarget_barabsolute);
final Scale BoostTarget_psirelativesealevel = new Scale();
BoostTarget_psirelativesealevel.setCategory("Standard");
BoostTarget_psirelativesealevel.setName("BoostTarget_psirelativesealevel");
BoostTarget_psirelativesealevel.setExpression("(x-760)*.01933677");
BoostTarget_psirelativesealevel.setByteExpression("(x/.01933677)+760");
BoostTarget_psirelativesealevel.setUnit("Boost Target (psi relative sea level)");
BoostTarget_psirelativesealevel.setFormat("0.00");
BoostTarget_psirelativesealevel.setCoarseIncrement(0.5);
BoostTarget_psirelativesealevel.setFineIncrement(0.01);
expectedScales.add(BoostTarget_psirelativesealevel);
final Scale rpm = new Scale();
rpm.setCategory("Default");
rpm.setName("rpm");
rpm.setExpression("x");
rpm.setByteExpression("x");
rpm.setUnit("RPM");
rpm.setFormat("#");
rpm.setCoarseIncrement(100.0);
rpm.setFineIncrement(50.0);
expectedScales.add(rpm);
final Scale targetboostcomppercent = new Scale();
targetboostcomppercent.setCategory("Default");
targetboostcomppercent.setName("targetboostcomppercent");
targetboostcomppercent.setExpression("(x*.78125)-100");
targetboostcomppercent.setByteExpression("(x+100)/.78125");
targetboostcomppercent.setUnit("raw value");
targetboostcomppercent.setFormat("0.0");
targetboostcomppercent.setCoarseIncrement(1.0);
targetboostcomppercent.setFineIncrement(0.4);
expectedScales.add(targetboostcomppercent);
final Scale WastegateDutyCycle_ = new Scale();
WastegateDutyCycle_.setCategory("Default");
WastegateDutyCycle_.setName("WastegateDutyCycle_%");
WastegateDutyCycle_.setExpression("x*.00390625");
WastegateDutyCycle_.setByteExpression("x/.00390625");
WastegateDutyCycle_.setUnit("Wastegate Duty Cycle (%)");
WastegateDutyCycle_.setFormat("0.0");
WastegateDutyCycle_.setCoarseIncrement(1.0);
WastegateDutyCycle_.setFineIncrement(0.2);
WastegateDutyCycle_.setMin(0.1);
WastegateDutyCycle_.setMax(99.9);
expectedScales.add(WastegateDutyCycle_);
return expectedScales;
}
}