Refactoring, technical debt: export more of trigger attributes into triggers.txt file #2077

This commit is contained in:
rusefillc 2022-04-02 20:48:19 -04:00
parent f8fe063415
commit 577b30c74a
10 changed files with 255 additions and 197 deletions

View File

@ -195,6 +195,7 @@ struct_no_prefix engine_configuration_s
#define TRIGGER_IS_SECOND_WHEEL_CAM "isSecondWheelCam"
#define TRIGGER_HAS_SECOND_CHANNEL "hasSecondChannel"
#define TRIGGER_HARDCODED_OPERATION_MODE "knownOperationMode"
#define TRIGGER_COMMENT "#"
!
! all the xxx_PACKING_xxx constants are about persisting tables in compact for, for example packing RPM with 50 increment in a byte

View File

@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="TriggerImage" type="Application" factoryName="Application" folderName="Trigger Renderer" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="com.rusefi.TriggerImage" />
<option name="MAIN_CLASS_NAME" value="com.rusefi.trigger.TriggerImage" />
<module name="ui" />
<option name="PROGRAM_PARAMETERS" value="../unit_tests" />
<extension name="coverage">

View File

@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="TriggerImage 27" type="Application" factoryName="Application" folderName="Trigger Renderer">
<option name="MAIN_CLASS_NAME" value="com.rusefi.TriggerImage" />
<option name="MAIN_CLASS_NAME" value="com.rusefi.trigger.TriggerImage" />
<module name="ui" />
<option name="PROGRAM_PARAMETERS" value="../unit_tests 27 10" />
<extension name="coverage">

View File

@ -1,22 +0,0 @@
package com.rusefi;
public class TriggerSignal {
final double angle;
final int state;
final int waveIndex;
public TriggerSignal(int waveIndex, int state, double angle) {
this.waveIndex = waveIndex;
this.state = state;
this.angle = angle;
}
@Override
public String toString() {
return "Signal{" +
"signal=" + waveIndex +
", state=" + state +
", angle=" + angle +
'}';
}
}

View File

@ -1,120 +0,0 @@
package com.rusefi;
import com.rusefi.enums.trigger_type_e;
import com.rusefi.trigger.WaveState;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
class TriggerWheelInfo {
final trigger_type_e id;
final double tdcPosition;
final String triggerName;
final List<WaveState> waves;
final List<TriggerSignal> signals;
private final boolean isCrankBased;
public TriggerWheelInfo(int id, double tdcPosition, String triggerName, List<WaveState> waves, List<TriggerSignal> signals, boolean isCrankBased) {
this.id = findByOrdinal(id);
this.tdcPosition = tdcPosition;
this.triggerName = triggerName;
this.waves = waves;
this.signals = signals;
this.isCrankBased = isCrankBased;
}
public static trigger_type_e findByOrdinal(int id) {
for (trigger_type_e type : trigger_type_e.values()) {
if (type.ordinal() == id)
return type;
}
throw new IllegalArgumentException("No type for " + id);
}
static TriggerWheelInfo readTriggerWheelInfo(String line, BufferedReader reader) throws IOException {
String[] tokens = line.split(" ");
String idStr = tokens[1];
int eventCount = Integer.parseInt(tokens[2]);
String triggerName = tokens[3];
System.out.println("Processing " + line + " " + idStr);
int id = Integer.parseInt(idStr);
double tdcPosition = Double.parseDouble(tokens[4]);
System.out.println("id=" + id + ", count=" + eventCount + ", name=" + triggerName);
line = reader.readLine();
String[] keyValue = line.split("=");
if (keyValue.length!=2)
throw new IllegalStateException("Key/value lines expected");
boolean isCrankBased = Boolean.valueOf(keyValue[1]);
List<TriggerSignal> signals = TriggerImage.readSignals(reader, eventCount);
List<WaveState> waves = TriggerImage.convertSignalsToWaves(signals);
return new TriggerWheelInfo(id, tdcPosition, triggerName, waves, signals, isCrankBased);
}
@NotNull
List<TriggerSignal> getFirstWheeTriggerSignals() {
List<TriggerSignal> firstWheel = getTriggerSignals(0);
// todo: support symmetrical crank
if (isCrankBased) {
return takeFirstHalf(firstWheel);
} else {
return compressAngle(firstWheel);
}
}
public double getTdcPositionIn360() {
return isCrankBased ? tdcPosition : getCompressedAngle(tdcPosition);
}
@NotNull
private List<TriggerSignal> getTriggerSignals(int index) {
return signals.stream().filter(signal -> signal.waveIndex == index).collect(Collectors.toList());
}
@NotNull
private List<TriggerSignal> takeFirstHalf(List<TriggerSignal> wheel) {
return wheel.stream().filter(triggerSignal -> triggerSignal.angle < 360).collect(Collectors.toList());
}
@NotNull
private static List<TriggerSignal> compressAngle(List<TriggerSignal> wheel) {
return wheel.stream().map(triggerSignal -> {
double compressAngle = getCompressedAngle(triggerSignal.angle);
return new TriggerSignal(triggerSignal.waveIndex, triggerSignal.state, compressAngle);
}).collect(Collectors.toList());
}
/**
* this is about converting 720 cycle of crank wheel shape into normal 360 circle range
*/
private static double getCompressedAngle(double angle) {
return angle / 2;
}
public List<TriggerSignal> getSecondWheeTriggerSignals() {
List<TriggerSignal> secondWheel = getTriggerSignals(1);
if (isSecondCamBased()) {
return compressAngle(secondWheel);
} else {
return takeFirstHalf(secondWheel);
}
}
// todo: this 'isFirstCrankBased' should be taken from triggers.txt not hard-coded here!
// todo: open question if current firmware even has info to provide this info or not?
// todo: https://github.com/rusefi/rusefi/issues/2077
private boolean isSecondCamBased() {
return id == trigger_type_e.TT_MAZDA_MIATA_NA ||
id == trigger_type_e.TT_MAZDA_DOHC_1_4 ||
id == trigger_type_e.TT_GM_60_2_2_2 ||
id == trigger_type_e.TT_FORD_ASPIRE;
}
}

View File

@ -1,8 +1,8 @@
package com.rusefi;
package com.rusefi.trigger;
import com.rusefi.StartupFrame;
import com.rusefi.config.generated.Fields;
import com.rusefi.enums.trigger_type_e;
import com.rusefi.trigger.WaveState;
import com.rusefi.ui.engine.UpDownImage;
import com.rusefi.ui.util.FrameHelper;
import com.rusefi.ui.util.UiUtils;
@ -50,7 +50,7 @@ public class TriggerImage {
* @see TriggerWheelInfo#isCrankBased
*/
private static String getTriggerName(TriggerWheelInfo triggerName) {
switch (triggerName.id) {
switch (findByOrdinal(triggerName.getId())) {
case TT_FORD_ASPIRE:
return "Ford Aspire";
case TT_VVT_BOSCH_QUICK_START:
@ -98,7 +98,7 @@ public class TriggerImage {
case TT_GM_60_2_2_2:
return "GM 60/2/2/2";
}
return triggerName.triggerName;
return triggerName.getTriggerName();
}
public static void main(String[] args) throws InvocationTargetException, InterruptedException {
@ -110,7 +110,7 @@ public class TriggerImage {
}
if (args.length > 1)
onlyOneTrigger = TriggerWheelInfo.findByOrdinal(Integer.parseInt(args[1]));
onlyOneTrigger = findByOrdinal(Integer.parseInt(args[1]));
if (args.length > 2)
sleepAtEnd = Integer.parseInt(args[2]);
@ -139,16 +139,16 @@ public class TriggerImage {
SwingUtilities.invokeAndWait(() -> {
try {
generateImages(workingFolder, triggerPanel, topPanel, content);
generateImages(workingFolder, wheelInfo -> onWheel(triggerPanel, topPanel, content, wheelInfo));
} catch (IOException e) {
throw new IllegalStateException(e);
}
});
Thread.sleep(1000 * sleepAtEnd);
Thread.sleep(1000L * sleepAtEnd);
System.exit(-1);
}
private static void generateImages(String workingFolder, TriggerPanel trigger, JPanel topPanel, JPanel content) throws IOException {
private static void generateImages(String workingFolder, TriggerWheelInfo.TriggerWheelInfoConsumer consumer) throws IOException {
String fileName = workingFolder + File.separator + Fields.TRIGGERS_FILE_NAME;
BufferedReader br = new BufferedReader(new FileReader(fileName));
@ -161,14 +161,19 @@ public class TriggerImage {
}
if (line.startsWith(TRIGGERTYPE)) {
readTrigger(br, line, trigger, topPanel, content);
readTrigger(br, line, consumer);
}
}
}
private static void readTrigger(BufferedReader reader, String line, TriggerPanel triggerPanel, JPanel topPanel, JPanel content) throws IOException {
private static void readTrigger(BufferedReader reader, String line, TriggerWheelInfo.TriggerWheelInfoConsumer consumer) throws IOException {
TriggerWheelInfo triggerWheelInfo = TriggerWheelInfo.readTriggerWheelInfo(line, reader);
if (onlyOneTrigger != null && triggerWheelInfo.id != onlyOneTrigger)
consumer.onWheel(triggerWheelInfo);
}
private static void onWheel(TriggerPanel triggerPanel, JPanel topPanel, JPanel content, TriggerWheelInfo triggerWheelInfo) {
if (onlyOneTrigger != null && findByOrdinal(triggerWheelInfo.getId()) != onlyOneTrigger)
return;
topPanel.removeAll();
@ -179,7 +184,9 @@ public class TriggerImage {
topPanel.add(firstWheelControl);
topPanel.add(StartupFrame.createLogoLabel());
if (!triggerWheelInfo.waves.get(1).list.isEmpty()) {
List<WaveState> waves = TriggerImage.convertSignalsToWaves(triggerWheelInfo.getSignals());
if (!waves.get(1).list.isEmpty()) {
JPanel secondWheelControl = createWheelPanel(triggerWheelInfo.getSecondWheeTriggerSignals(), false,
triggerWheelInfo);
topPanel.add(secondWheelControl);
@ -188,8 +195,7 @@ public class TriggerImage {
UiUtils.trueLayout(topPanel);
UiUtils.trueLayout(content);
triggerPanel.tdcPosition = triggerWheelInfo.tdcPosition;
List<WaveState> waves = triggerWheelInfo.waves;
triggerPanel.tdcPosition = triggerWheelInfo.getTdcPosition();
EngineReport re0 = new EngineReport(waves.get(0).list, MIN_TIME, 720 * (1 + EXTRA_COUNT));
System.out.println(re0);
@ -237,7 +243,7 @@ public class TriggerImage {
UiUtils.trueRepaint(triggerPanel);
content.paintImmediately(content.getVisibleRect());
new File(OUTPUT_FOLDER).mkdir();
UiUtils.saveImage(OUTPUT_FOLDER + File.separator + "trigger_" + triggerWheelInfo.id + ".png", content);
UiUtils.saveImage(OUTPUT_FOLDER + File.separator + "trigger_" + findByOrdinal(triggerWheelInfo.getId()) + ".png", content);
}
@NotNull
@ -269,7 +275,7 @@ public class TriggerImage {
for (int i = 0; i < wheel.size(); i++) {
TriggerSignal current = wheel.get(i);
drawRadialLine(g, current.angle);
drawRadialLine(g, current.getAngle());
/**
* java arc API is
* * Angles are interpreted such that 0&nbsp;degrees
@ -280,10 +286,10 @@ public class TriggerImage {
* we want zero to be at 12'clock position and clockwise rotation
*/
double nextAngle = i == wheel.size() - 1 ? 360 + wheel.get(0).angle : wheel.get(i + 1).angle;
int arcDuration = (int) (current.angle - nextAngle);
double nextAngle = i == wheel.size() - 1 ? 360 + wheel.get(0).getAngle() : wheel.get(i + 1).getAngle();
int arcDuration = (int) (current.getAngle() - nextAngle);
int arcStart = (int) arcToRusEFI(nextAngle);
if (current.state == 1) {
if (current.getState() == 1) {
g.drawArc(WHEEL_BORDER, WHEEL_BORDER, WHEEL_DIAMETER, WHEEL_DIAMETER, arcStart, arcDuration);
} else {
int corner = WHEEL_BORDER + (WHEEL_DIAMETER - SMALL_DIAMETER) / 2;
@ -330,7 +336,7 @@ public class TriggerImage {
List<TriggerSignal> toShow = new ArrayList<>(signals);
for (int i = 1; i <= 2 + EXTRA_COUNT; i++) {
for (TriggerSignal s : signals)
toShow.add(new TriggerSignal(s.waveIndex, s.state, s.angle + i * 720));
toShow.add(new TriggerSignal(s.getWaveIndex(), s.getState(), s.getAngle() + i * 720));
}
List<WaveState> waves = new ArrayList<>();
@ -339,10 +345,10 @@ public class TriggerImage {
waves.add(new WaveState());
for (TriggerSignal s : toShow) {
WaveState.trigger_value_e signal = (s.state == 0) ? WaveState.trigger_value_e.TV_LOW : WaveState.trigger_value_e.TV_HIGH;
WaveState.trigger_value_e signal = (s.getState() == 0) ? WaveState.trigger_value_e.TV_LOW : WaveState.trigger_value_e.TV_HIGH;
WaveState waveState = waves.get(s.waveIndex);
waveState.handle(signal, s.angle);
WaveState waveState = waves.get(s.getWaveIndex());
waveState.handle(signal, s.getAngle());
}
for (WaveState wave : waves)
wave.wrap();
@ -350,34 +356,13 @@ public class TriggerImage {
return waves;
}
@NotNull
static List<TriggerSignal> readSignals(BufferedReader reader, int count) throws IOException {
String line;
String[] tokens;
List<TriggerSignal> signals = new ArrayList<>();
int index = 0;
while (index < count) {
line = reader.readLine();
if (line.trim().startsWith("#"))
continue;
tokens = line.split(" ");
if (tokens.length < 4)
throw new IllegalStateException("Unexpected [" + line + "]");
int signalIndex = Integer.parseInt(tokens[2]);
int signalState = Integer.parseInt(tokens[3]);
double angle = Double.parseDouble(tokens[4]);
TriggerSignal s = new TriggerSignal(signalIndex, signalState, angle);
// System.out.println(s);
signals.add(s);
index++;
public static trigger_type_e findByOrdinal(int id) {
// todo: do we care about quicker implementation? probably not
for (trigger_type_e type : trigger_type_e.values()) {
if (type.ordinal() == id)
return type;
}
return signals;
}
public static int angleToTime(double prevUp) {
return (int) (prevUp);
throw new IllegalArgumentException("No type for " + id);
}
private static class TriggerPanel extends JPanel {

View File

@ -1,6 +1,5 @@
package com.rusefi.trigger;
import com.rusefi.TriggerImage;
import com.rusefi.waves.EngineReport;
import java.util.ArrayList;
@ -16,6 +15,10 @@ public class WaveState {
public List<EngineReport.UpDown> list = new ArrayList<>();
private static int angleToTime(double prevUp) {
return (int) (prevUp);
}
public enum trigger_value_e {
TV_LOW,
TV_HIGH
@ -28,7 +31,7 @@ public class WaveState {
// we have down before up, we would need to use it later
unusedDown = angle;
} else {
EngineReport.UpDown ud = new EngineReport.UpDown(TriggerImage.angleToTime(prevUp), 0, TriggerImage.angleToTime(angle), 0);
EngineReport.UpDown ud = new EngineReport.UpDown(angleToTime(prevUp), 0, angleToTime(angle), 0);
list.add(ud);
}
prevUp = Double.NaN;
@ -40,7 +43,7 @@ public class WaveState {
public void wrap() {
if (!Double.isNaN(unusedDown)) {
list.add(0, new EngineReport.UpDown(TriggerImage.angleToTime(prevUp), 0, TriggerImage.angleToTime(unusedDown + 720 * (3 + TriggerImage.EXTRA_COUNT)), 0));
list.add(0, new EngineReport.UpDown(angleToTime(prevUp), 0, angleToTime(unusedDown + 720 * (3 + TriggerImage.EXTRA_COUNT)), 0));
}
}
}

View File

@ -0,0 +1,34 @@
package com.rusefi.trigger;
public class TriggerSignal {
private final double angle;
private final int state;
private final int waveIndex;
public TriggerSignal(int waveIndex, int state, double angle) {
this.waveIndex = waveIndex;
this.state = state;
this.angle = angle;
}
@Override
public String toString() {
return "Signal{" +
"signal=" + getWaveIndex() +
", state=" + getState() +
", angle=" + getAngle() +
'}';
}
public double getAngle() {
return angle;
}
public int getState() {
return state;
}
public int getWaveIndex() {
return waveIndex;
}
}

View File

@ -0,0 +1,36 @@
package com.rusefi.trigger;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class TriggerSignalReader {
@NotNull
public static List<TriggerSignal> readSignals(BufferedReader reader, int count) throws IOException {
String line;
String[] tokens;
List<TriggerSignal> signals = new ArrayList<>();
int index = 0;
while (index < count) {
line = reader.readLine();
if (line.trim().startsWith("#"))
continue;
tokens = line.split(" ");
if (tokens.length < 4)
throw new IllegalStateException("Unexpected [" + line + "]");
int signalIndex = Integer.parseInt(tokens[2]);
int signalState = Integer.parseInt(tokens[3]);
double angle = Double.parseDouble(tokens[4]);
TriggerSignal s = new TriggerSignal(signalIndex, signalState, angle);
// System.out.println(s);
signals.add(s);
index++;
}
return signals;
}
}

View File

@ -0,0 +1,141 @@
package com.rusefi.trigger;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import static com.rusefi.config.generated.Fields.TRIGGER_IS_CRANK_KEY;
import static com.rusefi.config.generated.Fields.TRIGGER_IS_SECOND_WHEEL_CAM;
import static com.rusefi.config.generated.Fields.TRIGGER_HAS_SECOND_CHANNEL;
public class TriggerWheelInfo {
private final int id;
private final boolean isSecondWheelCam;
private final double tdcPosition;
private final String triggerName;
private final List<TriggerSignal> signals;
private final boolean isCrankBased;
public TriggerWheelInfo(int id, double tdcPosition, String triggerName, List<TriggerSignal> signals, boolean isCrankBased, boolean isSecondWheelCam) {
this.id = id;
this.isSecondWheelCam = isSecondWheelCam;
this.tdcPosition = tdcPosition;
this.triggerName = triggerName;
this.signals = signals;
this.isCrankBased = isCrankBased;
}
public static TriggerWheelInfo readTriggerWheelInfo(String line, BufferedReader reader) throws IOException {
String[] tokens = line.split(" ");
String idStr = tokens[1];
int eventCount = Integer.parseInt(tokens[2]);
String triggerName = tokens[3];
System.out.println("Processing " + line + " " + idStr);
int id = Integer.parseInt(idStr);
double tdcPosition = Double.parseDouble(tokens[4]);
System.out.println("id=" + id + ", count=" + eventCount + ", name=" + triggerName);
boolean isCrankBased = false;
boolean isSecondWheelCam = false;
while (true) {
line = reader.readLine();
if (line == null || line.trim().startsWith("#"))
break; // here we will read until first comment line which designates end of key-value pairs section
String[] keyValue = line.split("=");
if (keyValue.length != 2)
throw new IllegalStateException("Key/value lines expected");
switch (keyValue[0]) {
case TRIGGER_IS_CRANK_KEY:
isCrankBased = Boolean.parseBoolean(keyValue[1]);
break;
case TRIGGER_IS_SECOND_WHEEL_CAM:
isSecondWheelCam = Boolean.parseBoolean(keyValue[1]);
break;
case TRIGGER_HAS_SECOND_CHANNEL:
Boolean.parseBoolean(keyValue[1]);
break;
default:
throw new IllegalStateException("Unexpected key/value: " + line);
}
}
List<TriggerSignal> signals = TriggerSignalReader.readSignals(reader, eventCount);
return new TriggerWheelInfo(id, tdcPosition, triggerName, signals, isCrankBased, isSecondWheelCam);
}
@NotNull
public List<TriggerSignal> getFirstWheeTriggerSignals() {
List<TriggerSignal> firstWheel = getTriggerSignals(0);
// todo: support symmetrical crank
if (isCrankBased) {
return takeFirstHalf(firstWheel);
} else {
return compressAngle(firstWheel);
}
}
public double getTdcPositionIn360() {
return isCrankBased ? getTdcPosition() : getCompressedAngle(getTdcPosition());
}
@NotNull
private List<TriggerSignal> getTriggerSignals(int index) {
return getSignals().stream().filter(signal -> signal.getWaveIndex() == index).collect(Collectors.toList());
}
@NotNull
private List<TriggerSignal> takeFirstHalf(List<TriggerSignal> wheel) {
return wheel.stream().filter(triggerSignal -> triggerSignal.getAngle() < 360).collect(Collectors.toList());
}
@NotNull
private static List<TriggerSignal> compressAngle(List<TriggerSignal> wheel) {
return wheel.stream().map(triggerSignal -> {
double compressAngle = getCompressedAngle(triggerSignal.getAngle());
return new TriggerSignal(triggerSignal.getWaveIndex(), triggerSignal.getState(), compressAngle);
}).collect(Collectors.toList());
}
/**
* this is about converting 720 cycle of crank wheel shape into normal 360 circle range
*/
private static double getCompressedAngle(double angle) {
return angle / 2;
}
public List<TriggerSignal> getSecondWheeTriggerSignals() {
List<TriggerSignal> secondWheel = getTriggerSignals(1);
if (isSecondWheelCam) {
return compressAngle(secondWheel);
} else {
return takeFirstHalf(secondWheel);
}
}
public int getId() {
return id;
}
public double getTdcPosition() {
return tdcPosition;
}
public String getTriggerName() {
return triggerName;
}
public List<TriggerSignal> getSignals() {
return signals;
}
public interface TriggerWheelInfoConsumer {
void onWheel(TriggerWheelInfo wheelInfo);
}
}