/*
* 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.innovate.generic.mts.io;
import static com.romraider.logger.external.innovate.generic.mts.io.MTSSensorInputFunction.MTS_FUNC_LAMBDA;
import static com.romraider.logger.external.innovate.generic.mts.io.MTSSensorInputFunction.MTS_FUNC_NOTLAMBDA;
import static com.romraider.logger.external.innovate.generic.mts.io.MTSSensorInputFunction.MTS_FUNC_O2;
import static com.romraider.logger.external.innovate.generic.mts.io.MTSSensorInputType.MTS_TYPE_AFR;
import static com.romraider.logger.external.innovate.generic.mts.io.MTSSensorInputType.MTS_TYPE_LAMBDA;
import static com.romraider.logger.external.innovate.generic.mts.io.MTSSensorInputType.MTS_TYPE_VDC;
import static com.romraider.util.ThreadUtil.sleep;
import static java.lang.System.currentTimeMillis;
import static org.apache.log4j.Logger.getLogger;
import java.util.Map;
import org.apache.log4j.Logger;
import com.romraider.logger.external.core.Stoppable;
import com.romraider.logger.external.innovate.lm2.mts.plugin.Lm2MtsDataItem;
import com4j.EventCookie;
public final class MTSRunner implements MTSEvents, Stoppable {
private static final Logger LOGGER = getLogger(MTSRunner.class);
private final Map<Integer, Lm2MtsDataItem> dataItems;
private EventCookie connectionEventCookie;
private final MTS mts;
private boolean running;
private boolean stop;
private boolean pollMode;
/**
* MTSRunner contains the work-horse methods to process the MTS stream
* data and update the appropriate sensor result. Once started this class
* listens to NewData Events.
* If Event processing appears problematic set the pollmode option to true
* in the lm2_mts.plugin file to enable reading data from the MTS stream
* rather than waiting for NewData events.
*/
public MTSRunner(int mtsPort, Map<Integer,
Lm2MtsDataItem> dataItems,
boolean pollMode) {
MTSConnector connection = new MTSConnector(mtsPort);
this.mts = connection.getMts();
this.dataItems = dataItems;
this.pollMode = pollMode;
}
public void run() {
running = true;
try {
doRun();
} catch (Throwable t) {
LOGGER.error("Innovate MTS error occurred", t);
} finally {
running = false;
}
}
public void stop() {
stop = true;
// wait for it to stop running so mts can disconnect/dispose... timeout after 5secs
long timeout = currentTimeMillis() + 5000L;
while (running && currentTimeMillis() < timeout) sleep(100L);
}
private void doRun() {
try {
// attempt to connect to the specified device
connectionEventCookie = mts.advise(MTSEvents.class, this);
mts.connect();
try {
if (mts.inputCount() > 0) {
while (!stop) {
if (pollMode) readData();
sleep(40L);
}
}
else {
LOGGER.error("Innovate MTS: Error while reading data - no input channels found to log from!");
}
}
finally {
mts.disconnect();
}
}
finally {
connectionEventCookie.close();
mts.dispose();
}
}
public void connectionEvent(int result) {
if (result == 0) {
mts.startData();
LOGGER.debug("Innovate MTS connection success, pollmode:" + pollMode);
}
else if (result == -1) {
throw new IllegalStateException("No Innovate MTS Data detected");
}
else {
throw new IllegalStateException("Innovate MTS Connect Error: " + result);
}
}
public void connectionError() {
stop();
throw new IllegalStateException("Innovate MTS Connection Timeout");
}
public void newData() {
if(!pollMode) {
LOGGER.debug("Innovate MTS newData event");
readData();
}
}
public void readData() {
Lm2MtsDataItem dataItem;
int type;
int function;
int sample;
float data = 0.0f;
float min;
float max;
float multiplier;
try {
for (int i = 0; i < mts.inputCount(); i++) {
// select the input
dataItem = dataItems.get(i);
mts.currentInput(i);
type = mts.inputType();
function = mts.inputFunction();
sample = mts.inputSample();
// 5V channel
// Determine the range between min and max,
// calculate what percentage of that our sample represents,
// shift back to match our offset from 0.0 for min
if (type == MTS_TYPE_VDC.getType()) {
if (function == MTS_FUNC_NOTLAMBDA.getFunction()) {
min = dataItem.getMinValue();
max = dataItem.getMaxValue();
data = ((max - min) * ((float) sample / 1024f)) + min;
}
else {
// this will report other functions, such as ERROR states
// as a negative constant value
data = (float)function * -1f;
}
}
// AFR
// Take each sample step as .001 Lambda,
// add 0.5 (so our range is 0.5 to 1.523 for our 1024 steps),
// then multiply by the AFR multiplier
if (type == MTS_TYPE_AFR.getType()) {
if (function == MTS_FUNC_LAMBDA.getFunction()) {
multiplier = dataItem.getMultiplier();
data = ((float) sample / 1000f + 0.5f) * multiplier;
}
else if (function == MTS_FUNC_O2.getFunction()) {
data = ((float) sample / 10f);
}
else {
// this will report other functions, such as ERROR states
// as a negative constant value
data = (float)function * -1f;
}
}
// LAMBDA
// Identical to AFR, except we do not multiply for AFR.
if (type == MTS_TYPE_LAMBDA.getType()) {
if (function == MTS_FUNC_LAMBDA.getFunction()) {
data = (float) sample / 1000f + 0.5f;
}
else {
// this will report other functions, such as ERROR states
// as a negative constant value
data = (float)function * -1f;
}
}
// set data for this sensor based on inputNumber
if (dataItem != null) dataItem.setData(data);
final String result = String.format(
"Innovate MTS input: %d, type: %d, function: %d, sample: %d, result: %f",
i, type, function, sample, data);
LOGGER.trace(result);
}
}
catch (Exception e) {
LOGGER.error(String.format(
"Innovate MTS read data error: %s", e.toString()));
}
}
}