/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2016 RomRaider.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package com.romraider.logger.ecu.ui.tab.dyno;
import static com.romraider.Settings.COMMA;
import static com.romraider.Settings.SEMICOLON;
import static com.romraider.Version.CARS_DEFS_URL;
import static com.romraider.logger.car.util.SpeedCalculator.calculateMph;
import static com.romraider.logger.car.util.SpeedCalculator.calculateRpm;
import static com.romraider.logger.car.util.TorqueCalculator.calculateTorque;
import static com.romraider.util.ParamChecker.checkNotNull;
import static java.awt.GridBagConstraints.CENTER;
import static java.awt.GridBagConstraints.HORIZONTAL;
import static java.awt.GridBagConstraints.NONE;
import static javax.swing.JOptionPane.DEFAULT_OPTION;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
import static javax.swing.JOptionPane.showMessageDialog;
import static javax.swing.JOptionPane.showOptionDialog;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.border.TitledBorder;
import javax.swing.text.JTextComponent;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import com.romraider.Settings;
import com.romraider.editor.ecu.ECUEditor;
import com.romraider.logger.ecu.definition.EcuDataConvertor;
import com.romraider.logger.ecu.definition.EcuParameter;
import com.romraider.logger.ecu.definition.EcuSwitch;
import com.romraider.logger.ecu.definition.ExternalData;
import com.romraider.logger.ecu.definition.LoggerData;
import com.romraider.logger.ecu.ui.DataRegistrationBroker;
import com.romraider.net.BrowserControl;
import com.romraider.util.NumberUtil;
import com.romraider.util.SettingsManager;
public final class DynoControlPanel extends JPanel {
private static final long serialVersionUID = 3787020251963102201L;
private static final Logger LOGGER = Logger.getLogger(DynoControlPanel.class);
private static final String CARS_FILE = "cars_def.xml";
private static final String MISSING_CAR_DEF = "Missing cars_def.xml";
private static final String ENGINE_SPEED = "P8";
private static final String VEHICLE_SPEED = "P9";
private static final String IAT = "P11";
private static final String THROTTLE_ANGLE = "P13";
private static final String ATM = "P24";
private static final String MANUAL = "manual";
private static final String IMPERIAL = "Imperial";
private static final String METRIC = "Metric";
private static final String DYNO_MODE = "Dyno";
private static final String ET_MODE = "ET";
private static final String CAR_MASS_TT = "Base mass of car from factory";
private static final String DELTA_MASS_TT = "Mass of all occupants and accessories added";
private static final String HUMIDITY_TT = "Current relative Humidity";
private static final String TIRE_WIDTH_TT = "Tire width in millimeters";
private static final String TIRE_ASPECT_TT = "Tire aspect ratio in percentage";
private static final String WHEEL_SIZE_TT = "Wheel (rim) size in inches";
private static final String CAR_SELECT_TT = "Select car, default is first in list";
private static final String GEAR_SELECT_TT = "Select gear, default is 2nd for 4AT, 3rd for 5MT and 4th for 6MT";
private static final String RPM_MIN_TT = "RPM min is updated after WOT";
private static final String RPM_MAX_TT = "RPM max is updated after WOT";
private static final String ELEVATION_TT = "Elevation is calculated from ECU ATM sensor";
private static final String AMB_TEMP_TT = "Ambient Temperature is updated from IAT sensor";
private static final String ORDER_TT = "Lower number provides more smoothing";
private static final String RESET_TT = "This clears all recorded or file loaded data";
private static final String RECORD_TT = "Press to acquire data, multiple sets of Dyno data can be acquired";
private static final String DYNO_TT = "Use this mode to estimate Power & Torque";
private static final String ET_TT = "Use this mode to measure trap times";
private static final String COLON = ":";
private static final String TAB = "\u0009";
private static final String RR_LOG_TIME = "Time";
private static final String COBB_AP_TIME = "Seconds";
private static final String COBB_ATR_TIME = "Time Stamp";
private static final String AEM_LOG_TIME = "Time/s";
private static final String OP2_LOG_TIME = "time";
private static final String LOG_RPM = "RPM";
private static final String LOG_ES = "Engine Speed";
private static final String LOG_TA = "Throttle";
private static final String LOG_VS = "Vehicle Speed";
private static final String LOG_VS_I = "mph";
private static final String LOG_VS_M = "km/h";
private static final double KPH_2_MPH = 1.609344;
private final DataRegistrationBroker broker;
private final DynoChartPanel chartPanel;
private final Component parent;
private static FocusAdapter allTextSelector;
private List<ExternalData> externals = new ArrayList<ExternalData>();
private List<EcuParameter> params = new ArrayList<EcuParameter>();
private List<EcuSwitch> switches = new ArrayList<EcuSwitch>();
private String[] gearList;
private double tSize;
private double rpm2mph;
private double mass;
private double altitude;
private double humidity;
private double pressure;
private double airTemp;
private double pSat;
private double P_v;
private double P_d;
private double airDen;
private double fToE;
private double sToE;
private double tToS;
private double reFfToE;
private double reFsToE;
private double reFtToS;
private double reFauc;
private double auc;
private double aucStart;
private long fTime;
private long sTime;
private long eTime;
private long ttTime;
private long stTime;
private boolean getEnv;
private boolean wotSet;
private String path;
private String carInfo;
private String[] carTypeArr;
private String[] carMassArr;
private String[] dragCoeffArr;
private String[] rollCoeffArr;
private String[] frontalAreaArr;
private String[] gearRatioArr;
private String[][] gearsRatioArr;
private String[] finalRatioArr;
private String[] transArr;
private String[] widthArr;
private String[] aspectArr;
private String[] sizeArr;
private final JTextField carMass = new JTextField("0", 4);
private final JTextField deltaMass = new JTextField("225", 4);
private final JTextField dragCoeff = new JTextField("0", 4);
private final JTextField rollCoeff = new JTextField("0", 4);
private final JTextField frontalArea = new JTextField("0", 4);
private final JTextField rpmMin = new JTextField("2000", 4);
private final JTextField rpmMax = new JTextField("6500", 4);
private final JTextField elevation = new JTextField("200", 4);
private final JTextField relHumid = new JTextField("60", 4);
private final JTextField ambTemp = new JTextField("68", 4);
private final JTextField gearRatio = new JTextField("0", 4);
private final JTextField finalRatio = new JTextField("0", 4);
private final JTextField transmission = new JTextField("0", 4);
private final JTextField tireWidth = new JTextField("0", 4);
private final JTextField tireAspect = new JTextField("0", 4);
private final JTextField tireSize = new JTextField("0", 4);
private final JLabel elevLabel = new JLabel("Elevation (ft)");
private final JLabel tempLabel = new JLabel("Air Temperature (\u00b0F)");
private final JLabel deltaMassLabel = new JLabel("Delta Weight (lbs)");
private final JLabel carMassLabel = new JLabel("Base Weight (lbs)");
// private static final String SI = "SI";
private String units = IMPERIAL;
private String preUnits = IMPERIAL;
private String elevUnits = "ft";
private String tempUnits = "\u00b0F";
private double atm;
private String pressUnits = "psi";
private String pressText = String.format("%1.2f", 14.7);
private String iatLogUnits = "F";
private String atmLogUnits = "psi";
private String vsLogUnits = LOG_VS_I;
private final double[] results = new double[5];
private final String[] resultStrings = new String[6];
// private String hpUnits = "hp(I)";
// private String tqUnits = "lbf-ft";
private double distance;
private long lastET;
private final double[] etResults = new double[12];
private final JPanel filterPanel = new JPanel();
private final JPanel unitsPanel = new JPanel();
private final JPanel iPanel = new JPanel();
private final JPanel refPanel = new JPanel();
private final JPanel etPanel = new JPanel();
private final JComboBox orderComboBox = buildPolyOrderComboBox();
private final JComboBox carSelectBox = buildCarSelectComboBox();
private final JComboBox gearSelectBox = buildGearComboBox();
private final JButton interpolateButton = new JButton("Recalculate");
private final JToggleButton recordDataButton = new JToggleButton("Record Data");
private final JToggleButton recordButton = buildRecordDataButton();
private final JRadioButton dButton = new JRadioButton(DYNO_MODE);
private final JRadioButton eButton = new JRadioButton(ET_MODE);
private final JRadioButton iButton = new JRadioButton(IMPERIAL);
private final JRadioButton mButton = new JRadioButton(METRIC);
private final JCheckBox loadFileCB = new JCheckBox("Load From File");
public DynoControlPanel(Component parent, DataRegistrationBroker broker, ECUEditor ecuEditor, DynoChartPanel chartPanel) {
checkNotNull(parent, broker, chartPanel);
this.parent = parent;
this.broker = broker;
this.chartPanel = chartPanel;
addControls();
}
private void calculateEnv() {
if (units.equals(IMPERIAL)) {
altitude = parseDouble(elevation) * 0.3048; // feet to meters
airTemp = (parseDouble(ambTemp) + 459.67) * 5 / 9; //[K] = ([F] + 459.67) * 5/9
mass = (parseDouble(carMass) + parseDouble(deltaMass)) * 0.4536; //lbs to kg
pressure = atm * 6894.75728; // [Pa] = [psi] * 6894.75728
}
if (units.equals(METRIC)) {
altitude = parseDouble(elevation); // meters
airTemp = parseDouble(ambTemp) + 273.15; //[K] = [C] + 273.15
mass = (parseDouble(carMass) + parseDouble(deltaMass)); //kg
pressure = atm * 1000; // [Pa] = [kPa] * 1000
}
// if (units.equals(SI)) {
// altitude = parseDouble(elevation); // meters
// airTemp = parseDouble(ambTemp); //[K]
// mass = (parseDouble(carMass) + parseDouble(deltaMass)); //kg
// }
tSize = parseDouble(tireSize) + parseDouble(tireWidth) / 25.4 * parseDouble(tireAspect) / 100 * 2;
rpm2mph = parseDouble(gearRatio) * parseDouble(finalRatio) / (tSize * 0.002975);
humidity = parseDouble(relHumid) / 100;
// carInfo = (String) carSelectBox.getSelectedItem() + "(" + gearSelectBox.getSelectedItem() + "), Pres: " + pressText +
// pressUnits + ", Hum: " + relHumid.getText().trim() + "%, Temp: " + ambTemp.getText().trim() + tempUnits;
// Use elevation if ATM was not read from ECU
if (atm == 0) {
pressure = 101325 * Math.pow((1 - 22.5577 * Math.pow(10, -6) * altitude), 5.25578); //Pressure at altitude [Pa]
}
pSat = 610.78 * Math.pow(10, ((7.5 * airTemp - 2048.625) / (airTemp - 35.85))); //Saturation vapor pressure [Pa]
P_v = humidity * pSat;
P_d = pressure - P_v;
airDen = P_d / (287.05 * airTemp) + P_v / (461.495 * airTemp); //air density with humidity included [kg/m^3]
carInfo = carSelectBox.getSelectedItem() + "(" + gearSelectBox.getSelectedItem() + "); Elev: " + elevation.getText().trim() +
elevUnits + "; Pres: " + pressText + pressUnits + "; Hum: " + relHumid.getText().trim() + "%; Temp: " + ambTemp.getText().trim() + tempUnits;
}
private double calcHp(double rpm, double accel, long now) {
double mph = calculateMph(rpm, rpm2mph);
double accelG = accel * 45.5486542443;
// calculate Drive power = power required to propel vehicle mass at certain speed and acceleration.
// =Force*Velocity=Mass*Accel*Velocity
// Accel(m/s/s)*Mass(kg)*Velocity(m/s)
double dP = 9.8067 * accelG * mass * 0.44704 * mph;
// calculate Roll HP = Power required to counter rolling resistance
// Velocity(m/s)*Friction force
double rP = 0.44704 * mph * parseDouble(rollCoeff) * mass * 9.8067;
// calculate Wind HP = Power required to counter wind drag
// Aero drag
double aP = 0.5 * parseDouble(dragCoeff) * airDen * 0.0929 * parseDouble(frontalArea) * Math.pow(0.44704 * mph, 3);
double hp = dP + rP + aP;
if (units.equals(IMPERIAL)) {
hp = hp / 745.7;
}
if (units.equals(METRIC)) {
hp = hp / 1000;
}
// Calculate acceleration statistics
fTime = (mph <= 50) ? now : fTime;
sTime = (mph <= 60) ? now : sTime;
eTime = (mph <= 80) ? now : eTime;
ttTime = (rpm <= 3000) ? now : ttTime;
stTime = (rpm <= 6000) ? now : stTime;
fToE = (eTime - fTime) / 1000.0; // 50-80mph, sec
sToE = (eTime - sTime) / 1000.0; // 60-80mph, sec
tToS = (stTime - ttTime) / 1000.0; // 3-6k rpm, sec
return hp;
}
public double calcRpm(double vs) {
return calculateRpm(vs, rpm2mph, vsLogUnits);
}
public void updateEnv(double iat, double at_press) {
getEnv = false;
deregisterData(IAT, ATM);
if (units.equals(IMPERIAL)) {
if (iatLogUnits.equals("C")) iat = (iat * 9 / 5) + 32;
if (atmLogUnits.equals("bar")) at_press = at_press * 14.503773801;
if (at_press > 0) {
altitude = 145442 * (1 - Math.pow(((at_press / (1.45 * Math.pow(10, -2))) / 1013.25), 0.190263)); // Altitude in ft from ATM in psi
}
}
if (units.equals(METRIC)) {
if (iatLogUnits.equals("F")) iat = (iat - 32) * 5 / 9;
if (atmLogUnits.equals("bar")) {
if (at_press > 0) {
altitude = 145442 * (1 - Math.pow((((at_press * 14.503773801) / (1.45 * Math.pow(10, -2))) / 1013.25), 0.190263)) * 0.3048; // Altitude in m from ATM in psi
}
at_press = at_press * 100;
}
if (atmLogUnits.equals("psi")) {
if (at_press > 0) {
altitude = 145442 * (1 - Math.pow(((at_press / (1.45 * Math.pow(10, -2))) / 1013.25), 0.190263)) * 0.3048; // Altitude in m from ATM in psi
}
at_press = at_press * 6.89475728;
}
}
atm = at_press;
ambTemp.setText(String.format("%1.1f", iat));
pressText = String.format("%1.3f", atm);
if (atm > 0) {
elevation.setText(String.format("%1.0f", altitude));
}
// disable user input if ECU parameters recorded
// ambTemp.setEnabled(false);
elevation.setEnabled(false);
calculateEnv();
updateChart();
}
private void updateChart() {
chartPanel.quietUpdate(false);
auc = 0;
aucStart = 0;
double maxHp = 0;
double maxHpRpm = 0;
double maxTq = 0;
double maxTqRpm = 0;
double nowHp = 0;
double nowTq = 0;
int order = (Integer) orderComboBox.getSelectedItem();
double[] speedArray = Arrays.copyOf(chartPanel.getRpmCoeff(order), chartPanel.getRpmCoeff(order).length);
LOGGER.info("DYNO Speed Coeffecients: " + Arrays.toString(speedArray));
double[] accelArray = new double[(order)];
for (int x = 0; x < order; x++) {
accelArray[x] = (order - x) * speedArray[x];
}
LOGGER.info("DYNO Accel Coeffecients: " + Arrays.toString(accelArray));
int samples = chartPanel.getSampleCount();
LOGGER.info("DYNO Sample Count: " + samples);
double timeMin = chartPanel.getTimeSample(0);
double timeMax = chartPanel.getTimeSample(samples - 1);
for (double x = timeMin; x <= timeMax; x = x + 10) {
double speedSample = 0;
double accelSample = 0;
// Calculate smoothed SPEED from coefficients
for (int i = 0; i <= order; i++) {
int pwr = order - i;
speedSample = speedSample + (Math.pow(x, pwr) * speedArray[i]);
}
// Calculate acceleration from first derivative of SPEED coefficients
for (int i = 0; i < order; i++) {
int pwr = order - i - 1;
accelSample = accelSample + (Math.pow(x, pwr) * accelArray[i]);
}
if (isManual()) {
accelSample = accelSample / rpm2mph; // RPM acceleration from RPM
} else {
speedSample = calculateRpm(speedSample, rpm2mph, vsLogUnits); // convert logged vs to RPM for AT
if (vsLogUnits.equals(LOG_VS_M)) accelSample = accelSample / KPH_2_MPH;
}
if (checkInRange("RPM", rpmMin, rpmMax, speedSample)) {
nowHp = calcHp(speedSample, accelSample, (long) x);
nowTq = calculateTorque(speedSample, nowHp, units);
chartPanel.addData(speedSample, nowHp, nowTq);
if (nowHp > maxHp) {
maxHp = nowHp;
maxHpRpm = speedSample;
}
if (nowTq > maxTq) {
maxTq = nowTq;
maxTqRpm = speedSample;
}
if (speedSample >= 3000 && speedSample <= 6000) {
if (aucStart == 0) aucStart = (nowHp * speedSample) + (nowTq * speedSample);
auc = auc + Math.abs((nowHp * speedSample) + (nowTq * speedSample) - aucStart);
}
}
}
chartPanel.quietUpdate(true);
auc = auc / 1e6 / tToS;
results[0] = maxHp;
results[1] = maxHpRpm;
results[2] = maxTq;
results[3] = maxTqRpm;
String hpUnits = " hp(I)";
String tqUnits = " lbf-ft";
resultStrings[2] = "50-80 MPH: " + String.format("%1.2f", fToE) + " secs";
resultStrings[3] = "60-80 MPH: " + String.format("%1.2f", sToE) + " secs";
if (units.equals(METRIC)) {
hpUnits = " kW";
tqUnits = " N-m";
resultStrings[2] = "80-130 km/h: " + String.format("%1.2f", fToE) + " secs";
resultStrings[3] = "100-130 km/h: " + String.format("%1.2f", sToE) + " secs";
}
resultStrings[0] = carInfo;
resultStrings[1] = "Max Pwr: " + String.format("%1.1f", maxHp) + hpUnits +
" @ " + String.format("%1.0f", maxHpRpm) +
" RPM / Max TQ: " + String.format("%1.1f", maxTq) + tqUnits +
" @ " + String.format("%1.0f", maxTqRpm) + " RPM";
resultStrings[4] = "3000-6000 RPM: " + String.format("%1.2f", tToS) + " secs";
resultStrings[5] = "3000-6000 RPM: " + String.format("%1.2f", auc) + " AUC";
if (reFfToE > 0) resultStrings[2] = resultStrings[2] + " (" + String.format("%1.2f", (fToE - reFfToE)) + ")";
if (reFsToE > 0) resultStrings[3] = resultStrings[3] + " (" + String.format("%1.2f", (sToE - reFsToE)) + ")";
if (reFtToS > 0) resultStrings[4] = resultStrings[4] + " (" + String.format("%1.2f", (tToS - reFtToS)) + ")";
if (reFauc > 0) resultStrings[5] = resultStrings[5] + " (" + String.format("%1.2f", (auc - reFauc)) + ")";
LOGGER.info("DYNO Results: " + carInfo);
LOGGER.info("DYNO Results: " + resultStrings[1]);
LOGGER.info("DYNO Results: " + resultStrings[2]);
LOGGER.info("DYNO Results: " + resultStrings[3]);
LOGGER.info("DYNO Results: " + resultStrings[4]);
LOGGER.info("DYNO Results: " + resultStrings[5]);
chartPanel.interpolate(results, resultStrings);
parent.repaint();
}
private void updateET() {
chartPanel.quietUpdate(false);
int order = 5;
double x1 = 0;
distance = 0;
lastET = 0;
double[] speedArray = Arrays.copyOf(chartPanel.getRpmCoeff(order), chartPanel.getRpmCoeff(order).length);
LOGGER.info("DYNO Speed Coeffecients: " + Arrays.toString(speedArray));
int samples = chartPanel.getSampleCount();
LOGGER.info("DYNO Sample Count: " + samples);
double timeMin = chartPanel.getTimeSample(0);
double timeMax = chartPanel.getTimeSample(samples - 1);
for (double x = timeMin; x <= timeMax; x = x + 1) {
double speedSample = 0;
// Calculate smoothed SPEED from coefficients
for (int i = 0; i <= order; i++) {
int pwr = order - i;
speedSample = speedSample + (Math.pow(x, pwr) * speedArray[i]);
}
chartPanel.addData((x / 1000), speedSample);
if (vsLogUnits.equals(LOG_VS_M)) speedSample = (speedSample / KPH_2_MPH);
distance = distance + (speedSample * 5280 / 3600 * (x - lastET) / 1000);
lastET = (long) x;
x1 = x / 1000;
if (distance <= 60) etResults[0] = x1;
if (distance <= 60) etResults[1] = speedSample;
if (distance <= 330) etResults[2] = x1;
if (distance <= 330) etResults[3] = speedSample;
if (distance <= 660) etResults[4] = x1;
if (distance <= 660) etResults[5] = speedSample;
if (distance <= 1000) etResults[6] = x1;
if (distance <= 1000) etResults[7] = speedSample;
if (distance <= 1320) etResults[8] = x1;
if (distance <= 1320) etResults[9] = speedSample;
if (speedSample <= 60) etResults[10] = x1;
if (speedSample <= 60) etResults[11] = speedSample;
}
if (vsLogUnits.equals(LOG_VS_M)) {
etResults[1] = etResults[1] * KPH_2_MPH;
etResults[3] = etResults[3] * KPH_2_MPH;
etResults[5] = etResults[5] * KPH_2_MPH;
etResults[7] = etResults[7] * KPH_2_MPH;
etResults[9] = etResults[9] * KPH_2_MPH;
etResults[11] = etResults[11] * KPH_2_MPH;
}
chartPanel.quietUpdate(true);
LOGGER.info("ET Split 60: " + String.format("%1.3f", etResults[0]));
LOGGER.info("ET Split 330: " + String.format("%1.3f", etResults[2]));
LOGGER.info("ET Split 1/8: " + String.format("%1.3f", etResults[4]) + " @ " + String.format("%1.2f", etResults[5]));
LOGGER.info("ET Split 1000: " + String.format("%1.3f", etResults[6]));
LOGGER.info("ET Split 1/4: " + String.format("%1.3f", etResults[8]) + " @ " + String.format("%1.2f", etResults[9]));
LOGGER.info("ET 0 to " + String.format("%1.0f", etResults[11]) + " " + vsLogUnits + ": " + String.format("%1.3f", etResults[10]));
chartPanel.updateEtResults(carInfo, etResults, vsLogUnits);
parent.repaint();
}
public boolean isValidET(long now, double vs) {
try {
// LOGGER.trace("lastET: " + lastET + " now: " + now + " VS: " + vs);
if (vs > 0) {
if (vsLogUnits.equals(LOG_VS_M)) vs = (vs / KPH_2_MPH);
distance = distance + (vs * 5280 / 3600 * (now - lastET) / 1000);
LOGGER.info("ET Distance (ft): " + distance);
if (distance > 1330) {
recordDataButton.setSelected(false);
deregisterData(VEHICLE_SPEED);
chartPanel.clearPrompt();
updateET();
return false;
}
return true;
}
return false;
}
finally {
lastET = now;
}
}
public boolean isValidData(double rpm, double ta) {
if (wotSet && (ta < 99)) {
recordDataButton.setSelected(false);
rpmMax.setText(String.format("%1.0f", rpm));
deregister();
} else {
if (ta > 98) {
if (!wotSet) rpmMin.setText(String.format("%1.0f", rpm));
wotSet = true;
return true;
}
}
wotSet = false;
return false;
}
public boolean isManual() {
return transmission.getText().trim().equals(MANUAL);
}
private void deregister() {
if (isManual()) {
deregisterData(ENGINE_SPEED, THROTTLE_ANGLE);
} else {
deregisterData(VEHICLE_SPEED, THROTTLE_ANGLE);
}
registerData(IAT, ATM);
getEnv = true;
}
public boolean getEnv() {
return getEnv;
}
private void addControls() {
JPanel panel = new JPanel();
GridBagLayout gridBagLayout = new GridBagLayout();
panel.setLayout(gridBagLayout);
add(panel, gridBagLayout, buildModePanel(), 0, 0, 1, HORIZONTAL);
add(panel, gridBagLayout, buildFilterPanel(), 0, 1, 1, HORIZONTAL);
add(panel, gridBagLayout, buildRadioPanel(), 0, 2, 1, HORIZONTAL);
add(panel, gridBagLayout, buildInterpolatePanel(), 0, 3, 1, HORIZONTAL);
add(panel, gridBagLayout, buildReferencePanel(), 0, 4, 1, HORIZONTAL);
// add(panel, gridBagLayout, buildEtPanel(), 0, 5, 1, HORIZONTAL);
add(panel);
}
private void add(JPanel panel, GridBagLayout gridBagLayout, JComponent component, int x, int y, int spanX, int fillType) {
GridBagConstraints constraints = buildBaseConstraints();
updateConstraints(constraints, x, y, spanX, 1, 1, 1, fillType);
gridBagLayout.setConstraints(component, constraints);
panel.add(component);
}
private JPanel buildRadioPanel() {
// JPanel panel = new JPanel();
unitsPanel.setBorder(new TitledBorder("Measurement Units"));
GridBagLayout gridBagLayout = new GridBagLayout();
unitsPanel.setLayout(gridBagLayout);
buildRadioButtons(unitsPanel);
return unitsPanel;
}
private JPanel buildModePanel() {
JPanel panel = new JPanel();
panel.setBorder(new TitledBorder("Mode"));
GridBagLayout gridBagLayout = new GridBagLayout();
panel.setLayout(gridBagLayout);
buildModeButtons(panel);
return panel;
}
private JPanel buildInterpolatePanel() {
iPanel.setBorder(new TitledBorder("Recalculate"));
GridBagLayout gridBagLayout = new GridBagLayout();
iPanel.setLayout(gridBagLayout);
addLabeledComponent(iPanel, gridBagLayout, "Smoothing Factor", orderComboBox, 0);
addComponent(iPanel, gridBagLayout, buildInterpolateButton(orderComboBox), 2);
addMinMaxFilter(iPanel, gridBagLayout, "RPM Range", rpmMin, rpmMax, 4);
add(iPanel, gridBagLayout, elevLabel, 0, 6, 3, HORIZONTAL);
add(iPanel, gridBagLayout, elevation, 1, 7, 0, NONE);
add(iPanel, gridBagLayout, tempLabel, 0, 8, 3, HORIZONTAL);
add(iPanel, gridBagLayout, ambTemp, 1, 9, 0, NONE);
addLabeledComponent(iPanel, gridBagLayout, "Rel Humidity (%)", relHumid, 10);
setSelectAllFieldText(rpmMin);
setSelectAllFieldText(rpmMax);
setSelectAllFieldText(elevation);
setSelectAllFieldText(ambTemp);
setSelectAllFieldText(relHumid);
return iPanel;
}
private JPanel buildReferencePanel() {
refPanel.setBorder(new TitledBorder("Reference Trace"));
GridBagLayout gridBagLayout = new GridBagLayout();
refPanel.setLayout(gridBagLayout);
add(refPanel, gridBagLayout, buildOpenReferenceButton(), 0, 0, 1, NONE);
add(refPanel, gridBagLayout, buildSaveReferenceButton(), 1, 0, 1, NONE);
add(refPanel, gridBagLayout, buildClearReferenceButton(), 2, 0, 1, NONE);
return refPanel;
}
private JPanel buildEtPanel() {
etPanel.setBorder(new TitledBorder("Elapsed Time"));
etPanel.setVisible(false);
GridBagLayout gridBagLayout = new GridBagLayout();
etPanel.setLayout(gridBagLayout);
addLabeledComponent(etPanel, gridBagLayout, "Select Car", carSelectBox, 0);
addComponent(etPanel, gridBagLayout, recordButton, 2);
add(etPanel, gridBagLayout, buildSaveReferenceButton(), 1, 3, 1, NONE);
return etPanel;
}
private void addLabeledComponent(JPanel panel, GridBagLayout gridBagLayout, String name, JComponent component, int y) {
add(panel, gridBagLayout, new JLabel(name), 0, y, 3, HORIZONTAL);
add(panel, gridBagLayout, component, 0, y + 1, 3, NONE);
}
private JPanel buildFilterPanel() {
changeCars(0);
setToolTips();
filterPanel.setBorder(new TitledBorder("Dyno Settings"));
GridBagLayout gridBagLayout = new GridBagLayout();
filterPanel.setLayout(gridBagLayout);
add(filterPanel, gridBagLayout, new JLabel("Wheel (Width/Aspect-Diam.)"), 0, 15, 3, HORIZONTAL);
add(filterPanel, gridBagLayout, tireWidth, 0, 16, 1, NONE);
add(filterPanel, gridBagLayout, tireAspect, 1, 16, 1, NONE);
add(filterPanel, gridBagLayout, tireSize, 2, 16, 1, NONE);
addLabeledComponent(filterPanel, gridBagLayout, "Select Car", carSelectBox, 18);
addLabeledComponent(filterPanel, gridBagLayout, "Select Gear", gearSelectBox, 21);
add(filterPanel, gridBagLayout, deltaMassLabel, 0, 24, 3, HORIZONTAL);
add(filterPanel, gridBagLayout, deltaMass, 1, 25, 1, NONE);
add(filterPanel, gridBagLayout, carMassLabel, 0, 27, 3, HORIZONTAL);
add(filterPanel, gridBagLayout, carMass, 1, 28, 1, NONE);
addComponent(filterPanel, gridBagLayout, recordButton, 31);
addComponent(filterPanel, gridBagLayout, buildLoadFileCB(), 32);
addComponent(filterPanel, gridBagLayout, buildResetButton(), 33);
// addLabeledComponent(panel, gridBagLayout, "Drag Coeff", dragCoeff, 33);
// addLabeledComponent(panel, gridBagLayout, "Frontal Area", frontalArea, 36);
// addLabeledComponent(panel, gridBagLayout, "Rolling Resist Coeff", rollCoeff, 39);
setSelectAllFieldText(tireWidth);
setSelectAllFieldText(tireAspect);
setSelectAllFieldText(tireSize);
setSelectAllFieldText(deltaMass);
setSelectAllFieldText(carMass);
return filterPanel;
}
private void setToolTips() {
relHumid.setToolTipText(HUMIDITY_TT);
carMass.setToolTipText(CAR_MASS_TT);
deltaMass.setToolTipText(DELTA_MASS_TT);
tireWidth.setToolTipText(TIRE_WIDTH_TT);
tireAspect.setToolTipText(TIRE_ASPECT_TT);
tireSize.setToolTipText(WHEEL_SIZE_TT);
carSelectBox.setToolTipText(CAR_SELECT_TT);
gearSelectBox.setToolTipText(GEAR_SELECT_TT);
rpmMin.setToolTipText(RPM_MIN_TT);
rpmMax.setToolTipText(RPM_MAX_TT);
elevation.setToolTipText(ELEVATION_TT);
ambTemp.setToolTipText(AMB_TEMP_TT);
orderComboBox.setToolTipText(ORDER_TT);
recordDataButton.setToolTipText(RECORD_TT);
dButton.setToolTipText(DYNO_TT);
eButton.setToolTipText(ET_TT);
}
private JButton buildResetButton() {
JButton resetButton = new JButton("Clear Data");
resetButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
chartPanel.clear();
parent.repaint();
}
});
resetButton.setToolTipText(RESET_TT);
return resetButton;
}
private JToggleButton buildRecordDataButton() {
if (!carTypeArr[0].trim().equals(MISSING_CAR_DEF)) {
recordDataButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
elevation.setEnabled(true);
if (dButton.isSelected()) {
if (loadFileCB.isSelected()) {
loadFromFile();
} else {
if (recordDataButton.isSelected()) {
chartPanel.clearGraph();
parent.repaint();
calculateEnv();
if (isManual()) {
registerData(ENGINE_SPEED, THROTTLE_ANGLE);
} else {
registerData(VEHICLE_SPEED, THROTTLE_ANGLE);
}
chartPanel.startPrompt("wot");
} else {
recordDataButton.setSelected(false);
if (isManual()) {
deregisterData(ENGINE_SPEED, THROTTLE_ANGLE);
} else {
deregisterData(VEHICLE_SPEED, THROTTLE_ANGLE);
}
chartPanel.clearPrompt();
}
}
}
if (eButton.isSelected()) {
if (recordDataButton.isSelected()) {
chartPanel.clear();
parent.repaint();
calculateEnv();
registerData(VEHICLE_SPEED);
chartPanel.startPrompt(vsLogUnits);
distance = 0;
lastET = 0;
} else {
deregisterData(VEHICLE_SPEED);
recordDataButton.setSelected(false);
chartPanel.clearPrompt();
}
}
}
});
} else {
recordDataButton.setText(MISSING_CAR_DEF);
}
return recordDataButton;
}
private JCheckBox buildLoadFileCB() {
loadFileCB.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
if (loadFileCB.isSelected()) {
recordDataButton.setText("Read From File");
} else {
recordDataButton.setText("Record Data");
}
}
});
return loadFileCB;
}
public boolean isRecordData() {
return recordDataButton.isSelected();
}
public boolean isRecordET() {
return recordDataButton.isSelected() && eButton.isSelected();
}
private void buildModeButtons(JPanel panel) {
dButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
loadFileCB.setEnabled(true);
chartPanel.setDyno();
if (loadFileCB.isSelected()) {
recordDataButton.setText("Load From File");
} else {
recordDataButton.setText("Record Data");
}
// etPanel.setVisible(false);
// filterPanel.setVisible(true);
unitsPanel.setVisible(true);
iPanel.setVisible(true);
// refPanel.setVisible(true);
parent.repaint();
}
});
dButton.setSelected(true);
eButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
loadFileCB.setEnabled(false);
loadFileCB.setSelected(false);
chartPanel.setET();
recordDataButton.setText("Record ET");
// filterPanel.setVisible(false);
unitsPanel.setVisible(false);
iPanel.setVisible(false);
// refPanel.setVisible(false);
// etPanel.setVisible(true);
parent.repaint();
}
});
ButtonGroup group = new ButtonGroup();
group.add(dButton);
group.add(eButton);
panel.add(dButton);
panel.add(eButton);
}
private void buildRadioButtons(JPanel panel) {
iButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
buttonAction(iButton);
}
});
// iButton.setActionCommand(IMPERIAL);
iButton.setSelected(true);
mButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
buttonAction(mButton);
}
});
// mButton.setActionCommand(METRIC);
// final JRadioButton sButton = new JRadioButton(SI);
// sButton.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent actionEvent) {
// buttonAction(sButton);
// }
// });
// sButton.setActionCommand(SI);
//Group the radio buttons.
ButtonGroup group = new ButtonGroup();
group.add(iButton);
group.add(mButton);
// group.add(sButton);
panel.add(iButton);
panel.add(mButton);
// panel.add(sButton);
}
private void buttonAction(JRadioButton button) {
double result = 0;
units = button.getActionCommand();
if (units.equals(IMPERIAL)) {
if (preUnits.equals(METRIC)) {
result = parseDouble(ambTemp) * 9 / 5 + 32;
ambTemp.setText(String.format("%1.0f", result));
result = parseDouble(carMass) / 0.4536;
carMass.setText(String.format("%1.0f", result));
result = parseDouble(deltaMass) / 0.4536;
deltaMass.setText(String.format("%1.0f", result));
result = parseDouble(elevation) / 0.3048;
elevation.setText(String.format("%1.0f", result));
atm = atm / 6.89475728;
}
// if (preUnits.equals(SI)){
// result = parseDouble(ambTemp)* 9/5 - 459.67;
// ambTemp.setText(String.format("%1.0f", result));
// result = parseDouble(carMass) / 0.4536;
// carMass.setText(String.format("%1.0f", result));
// result = parseDouble(deltaMass) / 0.4536;
// deltaMass.setText(String.format("%1.0f", result));
// result = parseDouble(elevation) / 0.3048;
// elevation.setText(String.format("%1.0f", result));
// }
preUnits = IMPERIAL;
elevUnits = "ft";
tempUnits = "\u00b0F";
elevLabel.setText("Elevation (ft)");
tempLabel.setText("Air Temperature (\u00b0F)");
deltaMassLabel.setText("Delta Weight (lbs)");
carMassLabel.setText("Base Weight (lbs)");
pressText = String.format("%1.2f", atm);
pressUnits = "psi";
}
if (units.equals(METRIC)) {
if (preUnits.equals(IMPERIAL)) {
result = (parseDouble(ambTemp) - 32) * 5 / 9;
ambTemp.setText(String.format("%1.1f", result));
result = parseDouble(carMass) * 0.4536;
carMass.setText(String.format("%1.0f", result));
result = parseDouble(deltaMass) * 0.4536;
deltaMass.setText(String.format("%1.0f", result));
result = parseDouble(elevation) * 0.3048;
elevation.setText(String.format("%1.0f", result));
atm = atm * 6.89475728;
}
// if (preUnits.equals(SI)){
// result = parseDouble(ambTemp) - 273.15;
// ambTemp.setText(String.format("%1.1f", result));
// }
preUnits = METRIC;
elevUnits = "m";
tempUnits = "\u00b0C";
elevLabel.setText("Elevation (m)");
tempLabel.setText("Air Temperature (\u00b0C)");
deltaMassLabel.setText("Delta Weight (kg)");
carMassLabel.setText("Base Weight (kg)");
pressText = String.format("%1.2f", atm);
pressUnits = "kPa";
}
// if (units.equals(SI)) {
// if (preUnits.equals(IMPERIAL)){
// result = (parseDouble(ambTemp) + 459.67) * 5/9;
// ambTemp.setText(String.format("%1.1f", result));
// result = parseDouble(carMass) * 0.4536;
// carMass.setText(String.format("%1.0f", result));
// LOGGER.trace("units selcted: " + units + " result: " + result);
// result = parseDouble(deltaMass) * 0.4536;
// deltaMass.setText(String.format("%1.0f", result));
// result = parseDouble(elevation) * 0.3048;
// elevation.setText(String.format("%1.0f", result));
// }
// if (preUnits.equals(METRIC)){
// result = parseDouble(ambTemp) + 273.15;
// ambTemp.setText(String.format("%1.1f", result));
// }
// preUnits = SI;
// elevUnits = "m";
// tempUnits = "K";
// elevLabel.setText("Elevation (m)");
// tempLabel.setText("Air Temperature (K)");
// deltaMassLabel.setText("Delta Weight (kg)");
// carMassLabel.setText("Base Weight (kg)");
// }
if (resultStrings[0] != null) interpolateButton.doClick();
LOGGER.info("DYNO Measurement units selected: " + units);
}
private void loadFromFile() {
final JFileChooser openFile = new JFileChooser();
if (path != null) openFile.setCurrentDirectory(new File(path));
final JButton openButton = new JButton("Open");
int returnVal = openFile.showOpenDialog(openButton);
if (returnVal == JFileChooser.APPROVE_OPTION) {
final File logFile = openFile.getSelectedFile();
path = logFile.getParent();
BufferedReader inputStream = null;
recordDataButton.setSelected(false);
chartPanel.clearGraph();
parent.repaint();
calculateEnv();
try {
inputStream = new BufferedReader(new FileReader(logFile));
LOGGER.info("DYNO Opening log file: " + logFile.getName());
boolean atrTime = false;
double timeMult = 1;
double startTime = -999999999;
int timeCol = 0;
int rpmCol = 0;
int vsCol = 0;
int taCol = 0;
double minRpm = 3500;
double maxRpm = 0;
String delimiter = SEMICOLON;
String line = inputStream.readLine();
String[] headers;
headers = line.split(SEMICOLON);
if (headers.length < 3) {
headers = line.split(TAB);
if (headers.length > 2) {
delimiter = TAB;
}
else {
headers = line.split(COMMA);
if (headers.length > 2) delimiter = COMMA;
}
}
for (int x = 0; x < headers.length; x++) {
if (headers[x].contains(RR_LOG_TIME)) timeCol = x;
if (headers[x].contains(COBB_AP_TIME) ||
headers[x].contains(AEM_LOG_TIME) ||
headers[x].contains(OP2_LOG_TIME)) {
timeCol = x;
timeMult = 1000;
}
if (headers[x].contains(COBB_ATR_TIME)) {
timeCol = x;
timeMult = 1000;
atrTime = true;
}
if (headers[x].toUpperCase().contains(LOG_RPM) || headers[x].contains(LOG_ES)) rpmCol = x;
if (headers[x].contains(LOG_TA)) taCol = x;
if (headers[x].contains(LOG_VS)) vsCol = x;
if (headers[x].contains(LOG_VS_I)) vsLogUnits = LOG_VS_I;
if (headers[x].contains(LOG_VS_M)) vsLogUnits = LOG_VS_M;
}
LOGGER.trace("DYNO log file conversions: Time Column: " + timeCol + "; Time X: " + timeMult +
"; RPM Column: " + rpmCol + "; TA Column: " + taCol + "; VS Column: " + vsCol +
"; VS units: " + vsLogUnits);
while ((line = inputStream.readLine()) != null) {
String[] values = line.split(delimiter);
if (NumberUtil.doubleValue(values[taCol]) > 98) {
double logTime = 0;
if (atrTime) {
String[] timeStamp = values[timeCol].split(COLON);
if (timeStamp.length == 3) {
logTime = (NumberUtil.doubleValue(timeStamp[0]) * 3600) +
(NumberUtil.doubleValue(timeStamp[1]) * 60) +
NumberUtil.doubleValue(timeStamp[2]) * timeMult;
} else {
logTime = (NumberUtil.doubleValue(timeStamp[0]) * 60) +
NumberUtil.doubleValue(timeStamp[1]) * timeMult;
}
} else {
logTime = NumberUtil.doubleValue(values[timeCol]) * timeMult;
}
if (startTime == -999999999) startTime = logTime;
logTime = logTime - startTime;
double logRpm = 0;
if (isManual()) {
logRpm = NumberUtil.doubleValue(values[rpmCol]);
minRpm = Math.min(minRpm, logRpm);
maxRpm = Math.max(maxRpm, logRpm);
} else {
logRpm = NumberUtil.doubleValue(values[vsCol]);
minRpm = Math.min(minRpm, calculateRpm(logRpm, rpm2mph, vsLogUnits));
maxRpm = Math.max(maxRpm, calculateRpm(logRpm, rpm2mph, vsLogUnits));
}
chartPanel.addRawData(logTime, logRpm);
LOGGER.trace("DYNO log file time: " + logTime + "; speed: " + logRpm);
}
}
inputStream.close();
rpmMin.setText(String.format("%1.0f", minRpm));
rpmMax.setText(String.format("%1.0f", maxRpm));
interpolateButton.doClick();
}
catch (IOException e) {
e.printStackTrace();
}
catch (ParseException e) {
e.printStackTrace();
}
finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
} else {
LOGGER.info("DYNO Open log file command cancelled by user.");
}
}
private JButton buildOpenReferenceButton() {
final JFileChooser openFile = new JFileChooser();
if (path != null) openFile.setCurrentDirectory(new File(path));
final JButton openButton = new JButton("Open");
openButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
int returnVal = openFile.showOpenDialog(openButton);
if (returnVal == JFileChooser.APPROVE_OPTION) {
final File traceFile = openFile.getSelectedFile();
path = traceFile.getParent();
BufferedReader inputStream = null;
chartPanel.clearRefTrace();
try {
inputStream = new BufferedReader(new FileReader(traceFile));
LOGGER.info("DYNO Opening trace file: " + traceFile.getName());
String line = inputStream.readLine();
String[] refStats = line.split(TAB);
reFfToE = Double.parseDouble(refStats[3]);
reFsToE = Double.parseDouble(refStats[4]);
reFtToS = Double.parseDouble(refStats[5]);
reFauc = Double.parseDouble(refStats[6]);
LOGGER.info("DYNO Reference Stats: " + Arrays.toString(refStats));
while ((line = inputStream.readLine()) != null) {
String[] values = line.split(COMMA);
if (Double.parseDouble(values[0]) >= 0) {
chartPanel.setRefTrace(Double.parseDouble(values[0]), Double.parseDouble(values[1]), Double.parseDouble(values[2]));
}
}
inputStream.close();
if (refStats[0].equalsIgnoreCase(IMPERIAL)) {
iButton.setSelected(true);
buttonAction(iButton);
}
if (refStats[0].equalsIgnoreCase(METRIC)) {
mButton.setSelected(true);
buttonAction(mButton);
}
chartPanel.updateRefTrace(refStats);
}
catch (IOException e) {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
} else {
LOGGER.info("DYNO Open trace file command cancelled by user.");
}
}
});
return openButton;
}
private JButton buildSaveReferenceButton() {
final JFileChooser openFile = new JFileChooser();
if (path != null) openFile.setCurrentDirectory(new File(path));
final JButton saveButton = new JButton("Save");
saveButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
int returnVal = openFile.showSaveDialog(saveButton);
if (returnVal == JFileChooser.APPROVE_OPTION) {
final File traceFile = openFile.getSelectedFile();
path = traceFile.getParent();
BufferedWriter outputStream = null;
try {
if (dButton.isSelected()) {
outputStream = new BufferedWriter(new FileWriter(traceFile));
LOGGER.info("DYNO Saving trace to file: " + traceFile.getName());
String line = units + TAB + orderComboBox.getSelectedItem() +
TAB + resultStrings[1] +
TAB + fToE +
TAB + sToE +
TAB + tToS +
TAB + auc;
outputStream.write(line, 0, line.length());
outputStream.newLine();
for (int x = 0; x < chartPanel.getPwrTqCount(); x++) {
line = chartPanel.getPwrTq(x);
outputStream.write(line, 0, line.length());
outputStream.newLine();
}
}
if (eButton.isSelected()) {
outputStream = new BufferedWriter(new FileWriter(traceFile));
LOGGER.info("DYNO Saving ET to file: " + traceFile.getName());
String line = carInfo;
outputStream.write(line, 0, line.length());
outputStream.newLine();
line = "60ft/18.3m:" + TAB + String.format("%1.3f", etResults[0]) + "\" @ " + String.format("%1.2f", etResults[1]) + " " + vsLogUnits;
outputStream.write(line, 0, line.length());
outputStream.newLine();
line = "330ft/100m:" + TAB + String.format("%1.3f", etResults[2]) + "\" @ " + String.format("%1.2f", etResults[3]) + " " + vsLogUnits;
outputStream.write(line, 0, line.length());
outputStream.newLine();
line = "1/2 track:" + TAB + String.format("%1.3f", etResults[4]) + "\" @ " + String.format("%1.2f", etResults[5]) + " " + vsLogUnits;
outputStream.write(line, 0, line.length());
outputStream.newLine();
line = "1,000ft/305m:" + TAB + String.format("%1.3f", etResults[6]) + "\" @ " + String.format("%1.2f", etResults[7]) + " " + vsLogUnits;
outputStream.write(line, 0, line.length());
outputStream.newLine();
line = "1/4 mile/402m:" + TAB + String.format("%1.3f", etResults[8]) + "\" @ " + String.format("%1.2f", etResults[9]) + " " + vsLogUnits;
outputStream.write(line, 0, line.length());
outputStream.newLine();
}
outputStream.close();
}
catch (IOException e) {
try {
outputStream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
} else {
LOGGER.info("DYNO Save trace file command cancelled by user.");
}
}
});
return saveButton;
}
private JButton buildClearReferenceButton() {
final JButton clearButton = new JButton("Clear");
clearButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
reFfToE = 0;
reFsToE = 0;
reFtToS = 0;
reFauc = 0;
chartPanel.clearRefTrace();
if (results[0] > 0) interpolateButton.doClick();
}
});
return clearButton;
}
private void registerData(String... ids) {
for (String id : ids) {
LoggerData data = findData(id);
EcuDataConvertor convertor = data.getSelectedConvertor();
String convertorUnits = convertor.getUnits();
if (id.equals(ATM)) atmLogUnits = convertorUnits;
if (id.equals(IAT)) iatLogUnits = convertorUnits;
if (id.equals(VEHICLE_SPEED)) vsLogUnits = convertorUnits;
if (data != null) broker.registerLoggerDataForLogging(data);
}
}
private void deregisterData(String... ids) {
for (String id : ids) {
LoggerData data = findData(id);
if (data != null) broker.deregisterLoggerDataFromLogging(data);
}
}
private LoggerData findData(String id) {
for (EcuParameter param : params) {
if (id.equals(param.getId())) return param;
}
for (EcuSwitch sw : switches) {
if (id.equals(sw.getId())) return sw;
}
for (ExternalData external : externals) {
if (id.equals(external.getId())) return external;
}
return null;
}
private void addComponent(JPanel panel, GridBagLayout gridBagLayout, JComponent component, int y) {
add(panel, gridBagLayout, component, 0, y, 3, NONE);
}
private void addMinMaxFilter(JPanel panel, GridBagLayout gridBagLayout, String name, JTextField min, JTextField max, int y) {
add(panel, gridBagLayout, new JLabel(name), 0, y, 3, HORIZONTAL);
y += 1;
add(panel, gridBagLayout, min, 0, y, 2, NONE);
add(panel, gridBagLayout, new JLabel(" - "), 1, y, 0, NONE);
add(panel, gridBagLayout, max, 2, y, 1, NONE);
}
private GridBagConstraints buildBaseConstraints() {
GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = CENTER;
constraints.fill = NONE;
return constraints;
}
private void updateConstraints(GridBagConstraints constraints, int gridx, int gridy, int gridwidth, int gridheight, int weightx, int weighty, int fill) {
constraints.gridx = gridx;
constraints.gridy = gridy;
constraints.gridwidth = gridwidth;
constraints.gridheight = gridheight;
constraints.weightx = weightx;
constraints.weighty = weighty;
constraints.fill = fill;
}
private JButton buildInterpolateButton(final JComboBox orderComboBox) {
interpolateButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
if (dButton.isSelected()) {
interpolateButton.setEnabled(true);
if (isValidRange(rpmMin, rpmMax)) {
calculateEnv();
updateChart();
} else {
showMessageDialog(parent, "Invalid PRM range specified.", "Error", ERROR_MESSAGE);
}
}
}
});
return interpolateButton;
}
private JComboBox buildPolyOrderComboBox() {
final JComboBox orderComboBox = new JComboBox(new Object[]{5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19});
orderComboBox.setSelectedItem(9);
return orderComboBox;
}
private boolean areNumbers(JTextField... textFields) {
for (JTextField field : textFields) {
if (!isNumber(field)) return false;
}
return true;
}
private boolean checkInRange(String name, JTextField min, JTextField max, double value) {
if (isValidRange(min, max)) {
return inRange(value, min, max);
} else {
return false;
}
}
private boolean isValidRange(JTextField min, JTextField max) {
return areNumbers(min, max) && parseDouble(min) < parseDouble(max);
}
private boolean inRange(double value, JTextField min, JTextField max) {
return inRange(value, parseDouble(min), parseDouble(max));
}
private boolean inRange(double val, double min, double max) {
return val >= min && val <= max;
}
private boolean isNumber(JTextField textField) {
try {
parseDouble(textField);
return true;
} catch (Exception e) {
return false;
}
}
private double parseDouble(JTextField field) {
return Double.parseDouble(field.getText().trim());
}
public void setEcuParams(List<EcuParameter> params) {
this.params = new ArrayList<EcuParameter>(params);
}
public void setEcuSwitches(List<EcuSwitch> switches) {
this.switches = new ArrayList<EcuSwitch>(switches);
}
public void setExternalDatas(List<ExternalData> externals) {
this.externals = new ArrayList<ExternalData>(externals);
}
private JComboBox buildCarSelectComboBox() {
loadCars();
final JComboBox selectComboBox = new JComboBox(carTypeArr);
selectComboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
changeCars(selectComboBox.getSelectedIndex());
}
});
// carSelectBox.setSelectedItem("05 USDM OBXT WGN LTD 5MT");
return selectComboBox;
}
private JComboBox buildGearComboBox() {
// makeGearList();
final JComboBox gearSelectBox = new JComboBox();
gearSelectBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
gearRatio.setText(gearsRatioArr[carSelectBox.getSelectedIndex()][gearSelectBox.getSelectedIndex() + 1]);
LOGGER.info("DYNO Car: " + carSelectBox.getSelectedItem() + ", Changed gear to: " + gearSelectBox.getSelectedItem() + " (" + gearRatio.getText() + ")");
}
});
return gearSelectBox;
}
private void makeGearList() {
gearList = new String[Integer.valueOf(gearsRatioArr[carSelectBox.getSelectedIndex()][0])];
for (int g = 1; g <= Integer.valueOf(gearsRatioArr[carSelectBox.getSelectedIndex()][0]); g++) {
gearList[g - 1] = Integer.toString(g);
}
}
private void changeCars(int index) {
if (!carTypeArr[0].trim().equals(MISSING_CAR_DEF)) {
iButton.doClick();
carMass.setText(carMassArr[index]);
dragCoeff.setText(dragCoeffArr[index]);
rollCoeff.setText(rollCoeffArr[index]);
frontalArea.setText(frontalAreaArr[index]);
if (gearsRatioArr[index][0] == null) {
gearRatio.setText(gearRatioArr[index]);
} else {
// gearRatio.setText(gearsRatioArr[index][gearSelectBox.getSelectedIndex() + 1]);
gearRatio.setText(gearsRatioArr[index][1]);
}
finalRatio.setText(finalRatioArr[index]);
transmission.setText(transArr[index]);
tireWidth.setText(widthArr[index]);
tireAspect.setText(aspectArr[index]);
tireSize.setText(sizeArr[index]);
makeGearList();
LOGGER.info("DYNO New Car Selected: " + carSelectBox.getSelectedItem() + ", Gears: " + gearsRatioArr[carSelectBox.getSelectedIndex()][0]);
if (gearList == null) {
gearSelectBox.setModel(new DefaultComboBoxModel());
} else {
int gear = Integer.parseInt((gearsRatioArr[carSelectBox.getSelectedIndex()][0])) - 3;
gearSelectBox.setModel(new DefaultComboBoxModel(gearList));
gearSelectBox.setSelectedIndex(gear);
}
}
}
private void loadCars() {
try {
Settings settings = SettingsManager.getSettings();
File carDef = null;
final String SEPARATOR = System.getProperty("file.separator");
final String loggerFilePath = settings.getLoggerDefinitionFilePath();
if (loggerFilePath != null) {
final int index = loggerFilePath.lastIndexOf(SEPARATOR);
if (index > 0) {
final String path = loggerFilePath.substring(0, index + 1);
carDef = new File(path + CARS_FILE);
}
}
if (!carDef.exists()) {
final String profileFilePath = settings.getLoggerProfileFilePath();
if (profileFilePath != null) {
final int index = profileFilePath.lastIndexOf(SEPARATOR);
if (index > 0) {
final String path = profileFilePath.substring(0, index + 1);
carDef = new File(path + CARS_FILE);
}
}
}
if (!carDef.exists()) {
carDef = new File(CARS_FILE);
}
if (!carDef.exists()) {
throw new FileNotFoundException(MISSING_CAR_DEF);
}
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document carsDef = docBuilder.parse(carDef);
// normalize text representation
carsDef.getDocumentElement().normalize();
NodeList listOfCars = carsDef.getElementsByTagName("car");
int totalCars = listOfCars.getLength();
carTypeArr = new String[totalCars];
carMassArr = new String[totalCars];
dragCoeffArr = new String[totalCars];
rollCoeffArr = new String[totalCars];
frontalAreaArr = new String[totalCars];
gearRatioArr = new String[totalCars];
gearsRatioArr = new String[totalCars][7];
finalRatioArr = new String[totalCars];
transArr = new String[totalCars];
widthArr = new String[totalCars];
aspectArr = new String[totalCars];
sizeArr = new String[totalCars];
String[] tag = {"type", "carmass", "dragcoeff", "rollcoeff", "frontalarea",
"finalratio", "transmission", "tirewidth", "tireaspect", "wheelsize"};
for (int s = 0; s < listOfCars.getLength(); s++) {
Node carNode = listOfCars.item(s);
if (carNode.getNodeType() == Node.ELEMENT_NODE) {
Element carElement = (Element) carNode;
// Read element types and populate arrays
for (int i = 0; i < tag.length; i++) {
NodeList list = carElement.getElementsByTagName(tag[i]);
Element element = (Element) list.item(0);
if (element != null) {
NodeList value = element.getChildNodes();
String data = value.item(0).getNodeValue().trim();
switch (i) {
case 0:
carTypeArr[s] = data;
// gearRatioArr[s] = data;
for (int g = 1; g <= 6; g++) {
String gearNo = "gearratio" + g;
NodeList grsList = carElement.getElementsByTagName(gearNo);
Element carGrsElement = (Element) grsList.item(0);
if (carGrsElement != null) {
NodeList grsValueList = carGrsElement.getChildNodes();
if (grsValueList.item(0).getNodeValue().trim() != null) {
gearsRatioArr[s][0] = Integer.toString(g);
gearsRatioArr[s][g] = grsValueList.item(0).getNodeValue().trim();
}
}
// LOGGER.trace("Car: " + s + " Gear: " + g + " Ratio: " + gearsRatioArr[s][g]);
}
break;
case 1:
carMassArr[s] = data;
break;
case 2:
dragCoeffArr[s] = data;
break;
case 3:
rollCoeffArr[s] = data;
break;
case 4:
frontalAreaArr[s] = data;
break;
case 5:
finalRatioArr[s] = data;
break;
case 6:
transArr[s] = data;
break;
case 7:
widthArr[s] = data;
break;
case 8:
aspectArr[s] = data;
break;
case 9:
sizeArr[s] = data;
break;
}
}
}
}
}
}
catch (SAXParseException err) {
showMessageDialog(parent, "Parsing error" + ", line " + err.getLineNumber() + ", " + err.getSystemId() + ".\n" + err.getMessage(), "Error", ERROR_MESSAGE);
LOGGER.error("DYNO ** Parsing error" + ", line " + err.getLineNumber() + ", uri " + err.getSystemId());
LOGGER.error(" " + err.getMessage());
}
catch (SAXException e) {
Exception x = e.getException();
((x == null) ? e : x).printStackTrace();
}
catch (Throwable t) { // file not found
Object[] options = {"Yes", "No"};
int answer = showOptionDialog(this,
"Cars definition file not found.\nGo online to download the latest definition file?",
"Configuration", DEFAULT_OPTION, WARNING_MESSAGE, null, options, options[0]);
if (answer == 0) {
BrowserControl.displayURL(CARS_DEFS_URL);
} else {
showMessageDialog(parent, MISSING_CAR_DEF +
" file from the installation or profiles or definitions directory.\nDyno feature will not be available until this file is present.", "Notice", WARNING_MESSAGE);
}
carTypeArr = new String[]{MISSING_CAR_DEF};
t.printStackTrace();
}
}
private static void setSelectAllFieldText(JTextComponent comp) {
// Ensures that all the text in a JTextComponent will be
// selected whenever the cursor is in that field (gains focus):
if (allTextSelector == null) {
allTextSelector = new java.awt.event.FocusAdapter() {
@Override
public void focusGained(FocusEvent ev) {
JTextComponent textComp = (JTextComponent) ev.getSource();
textComp.selectAll();
}
};
}
comp.addFocusListener(allTextSelector);
}
}