/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2015 RomRaider.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package com.romraider.logger.external.ecotrons.io;
import static com.romraider.util.ByteUtil.byteListToBytes;
import static com.romraider.util.HexUtil.asHex;
import static org.apache.log4j.Logger.getLogger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import com.romraider.logger.external.core.Stoppable;
import com.romraider.logger.external.ecotrons.plugin.AlmDataItem;
import com.romraider.logger.external.ecotrons.plugin.AlmDataProcessor;
import com.romraider.logger.external.ecotrons.plugin.AlmSensorType;
public final class AlmRunner implements Stoppable {
private static final Logger LOGGER = getLogger(AlmRunner.class);
private static final byte[] CONNECT_CMD = {
(byte) 0x80, (byte) 0x8F, (byte) 0xEA, 0x03, (byte) 0x9C, 0x01, 0x00, (byte) 0x99};
private static final byte[] START_CMD = {
(byte) 0x80, (byte) 0x8F, (byte) 0xEA, 0x03, (byte) 0x9C, 0x0D, 0x00, (byte) 0xA5};
private static final byte[] STOP_CMD = {
(byte) 0x80, (byte) 0x8F, (byte) 0xEA, 0x03, (byte) 0x9C, 0x09, 0x00, (byte) 0xA5};
private final AlmConnection connection;
private final Map<AlmSensorType, AlmDataItem> dataItems;
private boolean stop;
private boolean init = true;
private boolean error;
private int stage;
public AlmRunner(String port, Map<AlmSensorType, AlmDataItem> dataItems) {
connection = new AlmSerialConnection(port);
this.dataItems = dataItems;
}
public void run() {
try {
int length = 0;
boolean packetStarted = false;
final List<Byte> buffer = new ArrayList<Byte>(64);
while (!stop) {
if (stage == 0 && init) {
connection.write(CONNECT_CMD);
init = false;
}
if (stage == 1 && init) {
connection.write(START_CMD);
init = false;
}
byte b = connection.readByte();
if (b == (byte) 0x8F
&& buffer.size() >= 1
&& buffer.get(buffer.size() - 1) == (byte) 0x80) {
packetStarted = false;
buffer.add(b);
}
else if (b == (byte) 0xEA
&& buffer.size() >= 2
&& buffer.get(buffer.size() - 1) == (byte) 0x8F
&& buffer.get(buffer.size() - 2) == (byte) 0x80) {
packetStarted = true;
error = false;
buffer.add(b);
}
else if (packetStarted && length == 0) {
buffer.add(b);
length = b;
final byte[] bytes = new byte[length + 1];
connection.readBytes(bytes);
for (byte data : bytes) {
buffer.add(data);
}
}
else if (error && (b != (byte) 0x80)) {
buffer.clear();
}
else {
buffer.add(b);
}
if (buffer.size() == (length + 5)) {
final byte cs = AlmChecksumCalculator.calculateChecksum(buffer);
if (cs == buffer.get(buffer.size() - 1)) {
if (stage == 0) {
if (buffer.get(4) == (byte) 0xE5
&& buffer.get(5) == (byte) 0x01) {
LOGGER.trace(String.format(
"Stage:%d, ALM Connect response:%s",
stage, asHex(toArray(buffer))));
stage = 1;
error = false;
init = true;
}
else {
error = true;
init = false;
}
}
else if (stage > 0) {
if (buffer.get(4) == (byte) 0xE5
&& buffer.get(5) == (byte) 0x0D) {
LOGGER.trace(String.format(
"Stage:%d, ALM measuring response:%s",
stage, asHex(toArray(buffer))));
stage = 2;
error = false;
init = true;
AlmDataProcessor.parseResponse(dataItems, buffer);
}
else {
error = true;
init = false;
}
}
}
else {
error = true;
LOGGER.error(String.format(
"Stage:%d, ALM checksum failure:%s, expected:%02X",
stage, asHex(toArray(buffer)), cs));
}
buffer.clear();
packetStarted = false;
length = 0;
}
}
}
catch (Throwable t) {
LOGGER.error("Error occurred", t);
}
finally {
if (stage == 2) {
error = false;
init = true;
stage = 0;
connection.write(STOP_CMD);
final byte[] response = new byte[8];
connection.readBytes(response);
LOGGER.trace(String.format(
"Stage:%d, ALM stop response:%s",
stage, asHex(response)));
}
connection.close();
}
}
public void stop() {
stop = true;
}
private byte[] toArray(List<Byte> buffer) {
final byte[] response = new byte[buffer.size()];
byteListToBytes(buffer, response);
return response;
}
}