package com.rusefi.f4discovery; import com.rusefi.config.generated.Fields; import com.rusefi.RusefiTestBase; import com.rusefi.core.Sensor; import com.rusefi.core.SensorCentral; import com.rusefi.enums.SensorType; import com.rusefi.enums.engine_type_e; import com.rusefi.functional_tests.EcuTestHelper; import com.rusefi.waves.EngineChart; import org.junit.Test; import java.util.Arrays; import static com.rusefi.IoUtil.getEnableCommand; import static com.rusefi.TestingUtils.assertNull; import static com.rusefi.config.generated.Fields.CMD_SET_SENSOR_MOCK; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** * rusEFI firmware simulator functional test suite *

* java -cp rusefi_console.jar com.rusefi.AutoTest * * @author Andrey Belomutskiy * 3/5/14 */ public class CommonFunctionalTest extends RusefiTestBase { @Test public void testChangingIgnitionMode() { ecu.setEngineType(engine_type_e.FORD_ASPIRE_1996); ecu.changeRpm(2000); // First is wasted spark ecu.sendCommand("set ignition_mode 2"); { // Check that we're in wasted spark mode EngineChart chart = nextChart(); // Wasted spark should fire cylinders 1/3... assertWaveNotNull(chart, EngineChart.SPARK_1, EngineChart.SPARK_3 ); // ...but not cylinders 2/4 assertWaveNull(chart, EngineChart.SPARK_2, EngineChart.SPARK_4 ); } // Now switch to sequential mode ecu.sendCommand("set ignition_mode 1"); { // Check that we're in sequential spark mode EngineChart chart = nextChart(); // All 4 cylinders should be firing assertWaveNotNull(chart, EngineChart.SPARK_1, EngineChart.SPARK_2, EngineChart.SPARK_3, EngineChart.SPARK_4 ); } // Now switch to "one coil" mode ecu.sendCommand("set ignition_mode 0"); { // Check that we're in sequential spark mode EngineChart chart = nextChart(); // Only coil 1 should be active assertWaveNotNull(chart, EngineChart.SPARK_1); // And no others assertWaveNull(chart, EngineChart.SPARK_2, EngineChart.SPARK_3, EngineChart.SPARK_4 ); } // Now switch BACK to wasted mode ecu.sendCommand("set ignition_mode 2"); { // Check that we're in wasted spark mode EngineChart chart = nextChart(); // Wasted spark should fire cylinders 1/3... assertWaveNotNull(chart, EngineChart.SPARK_1, EngineChart.SPARK_3 ); // ...but not cylinders 2/4 assertWaveNull(chart, EngineChart.SPARK_2, EngineChart.SPARK_4 ); } } @Test public void testRevLimiter() { ecu.setEngineType(engine_type_e.FORD_ASPIRE_1996); ecu.changeRpm(2000); // Alpha-N mode so that we actually inject some fuel (without mocking tons of sensors) ecu.sendCommand("set algorithm 2"); // Set tps to 25% - make alpha-n happy ecu.sendCommand(CMD_SET_SENSOR_MOCK + " " + SensorType.Tps1.ordinal() + " 25"); ecu.sendCommand("set rpm_hard_limit 2500"); { // Check that neither ignition nor injection is cut EngineChart chart = nextChart(); assertWaveNotNull(chart, EngineChart.SPARK_1, EngineChart.INJECTOR_1 ); } // Now go above the hard limiter ecu.changeRpm(3000); { // Check that both ignition and injection are cut EngineChart chart = nextChart(); // These channels are allowed to have falling edges - aka closing injectors and firing coils // but not allowed to have rising edges - aka opening injectors and charging coils assertWaveNoRises(chart, EngineChart.SPARK_1, EngineChart.INJECTOR_1 ); } // Check that it recovers when we go back under the limit ecu.changeRpm(2000); { // Check that neither ignition nor injection is cut EngineChart chart = nextChart(); assertWaveNotNull(chart, EngineChart.SPARK_1, EngineChart.INJECTOR_1 ); } } @Test public void testCustomEngine() { ecu.setEngineType(engine_type_e.DEFAULT_FRANKENSO); ecu.sendCommand("set_toothed_wheel 4 0"); // sendCommand("enable trigger_only_front"); // changeRpm(100); // changeRpm(1500); // sendCommand("disable trigger_only_front"); // changeRpm(100); // changeRpm(1500); } @Test public void testAuxValveNissan() { ecu.setEngineType(engine_type_e.NISSAN_PRIMERA); ecu.changeRpm(1200); } @Test public void testTwoStrokeSachs() { ecu.setEngineType(engine_type_e.SACHS); ecu.changeRpm(1200); } @Test public void test2003DodgeNeon() { ecu.setEngineType(engine_type_e.DODGE_NEON_2003_CRANK); ecu.sendCommand("set wwaeTau 0"); ecu.sendCommand("set wwaeBeta 0"); ecu.sendCommand(CMD_SET_SENSOR_MOCK + " " + SensorType.Map.ordinal() + " 69.12"); ecu.sendCommand(CMD_SET_SENSOR_MOCK + " " + SensorType.BatteryVoltage.ordinal() + " 12"); ecu.sendCommand("disable cylinder_cleanup"); EngineChart chart; String msg = "2003 Neon cranking "; ecu.changeRpm(200); ecu.changeRpm(250); // another approach to artificial delay ecu.changeRpm(200); EcuTestHelper.assertSomewhatClose("VBatt", 12, SensorCentral.getInstance().getValue(Sensor.VBATT)); chart = nextChart(); double x = 100; assertWaveNotNull(msg, chart, EngineChart.SPARK_1); assertWaveNull(msg, chart, EngineChart.SPARK_2); assertWaveNotNull(msg, chart, EngineChart.SPARK_3); assertWaveNull(msg, chart, EngineChart.SPARK_4); x = 176.856; // todo: why is width precision so low here? is that because of loaded Windows with 1ms precision? double widthRatio = 0.25; // WAT? this was just 0.009733333333333387? assertWaveNotNull(msg, chart, EngineChart.INJECTOR_1); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_2); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_3); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_4); msg = "2003 Neon running"; ecu.changeRpm(2000); ecu.changeRpm(2700); ecu.changeRpm(2000); chart = nextChart(); x = 104.0; assertWaveNotNull(msg, chart, EngineChart.SPARK_1); assertWaveNull(msg, chart, EngineChart.SPARK_2); assertWaveNotNull(msg, chart, EngineChart.SPARK_3); assertWaveNull(msg, chart, EngineChart.SPARK_4); chart = nextChart(); x = 74; assertWaveNotNull(msg, chart, EngineChart.INJECTOR_1); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_2); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_3); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_4); ecu.sendCommand(getEnableCommand("trigger_only_front")); chart = nextChart(); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_1); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_2); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_3); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_4); ecu.sendCommand("set_whole_timing_map 520"); chart = nextChart(); x = 328; assertWaveNotNull(msg, chart, EngineChart.SPARK_1); ecu.sendCommand("set_whole_timing_map 0"); chart = nextChart(); x = 128; assertWaveNotNull(msg, chart, EngineChart.SPARK_1); } @Test public void testMazdaProtege() { ecu.setEngineType(engine_type_e.FORD_ESCORT_GT); EngineChart chart; ecu.sendCommand(CMD_SET_SENSOR_MOCK + " " + SensorType.BatteryVoltage.ordinal() + " 12"); // Alpha-N mode so that we actually inject some fuel (without mocking tons of sensors) ecu.sendCommand("set algorithm 2"); // Set tps to 25% - make alpha-n happy ecu.sendCommand(CMD_SET_SENSOR_MOCK + " " + SensorType.Tps1.ordinal() + " 25"); ecu.changeRpm(200); ecu.changeRpm(260); ecu.changeRpm(200); String msg = "ProtegeLX cranking"; chart = nextChart(); EcuTestHelper.assertSomewhatClose("", 12, SensorCentral.getInstance().getValue(Sensor.VBATT), 0.1); assertWaveNotNull(msg, chart, EngineChart.SPARK_3); assertWaveNotNull(msg, chart, EngineChart.SPARK_1); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_1); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_2); msg = "ProtegeLX running"; ecu.changeRpm(2000); chart = nextChart(); assertWaveNotNull(msg, chart, EngineChart.SPARK_1); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_1); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_2); } @Test public void test1995DodgeNeon() { ecu.setEngineType(engine_type_e.DODGE_NEON_1995); EngineChart chart; sendComplexCommand(Fields.CMD_INDIVIDUAL_INJECTION); /** * note that command order matters - RPM change resets wave chart */ ecu.changeRpm(2000); chart = nextChart(); String msg = "1995 Neon"; //assertWaveNotNull(msg, chart, EngineChart.INJECTOR_4); //assertWaveNotNull(msg, chart, EngineChart.INJECTOR_2); //assertWaveNotNull(msg, chart, EngineChart.INJECTOR_1); //assertWaveNotNull(msg, chart, EngineChart.INJECTOR_3); assertWaveNotNull(msg, chart, EngineChart.SPARK_4); assertWaveNotNull(msg, chart, EngineChart.SPARK_2); assertWaveNotNull(msg, chart, EngineChart.SPARK_1); assertWaveNotNull(msg, chart, EngineChart.SPARK_3); // switching to Speed Density ecu.sendCommand(CMD_SET_SENSOR_MOCK + " " + SensorType.Map.ordinal() + " 69.12"); sendComplexCommand("set algorithm 0"); ecu.changeRpm(2600); ecu.changeRpm(2000); chart = nextChart(); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_4); } @Test public void testFord6() { ecu.setEngineType(engine_type_e.FORD_INLINE_6_1995); EngineChart chart; ecu.changeRpm(2000); chart = nextChart(); String msg = "ford 6"; assertWaveNotNull(msg, chart, EngineChart.SPARK_1); assertWaveNull(msg, chart, EngineChart.TRIGGER_2); sendComplexCommand("set " + "trigger_type" + " " + com.rusefi.enums.trigger_type_e.TT_FORD_ASPIRE.ordinal()); chart = nextChart(); assertTrue(chart.get(EngineChart.TRIGGER_2) != null); } @Test public void testFordAspire() { ecu.setEngineType(engine_type_e.FORD_ASPIRE_1996); ecu.sendCommand("disable cylinder_cleanup"); ecu.sendCommand(CMD_SET_SENSOR_MOCK + " " + SensorType.Map.ordinal() + " 69.12"); ecu.sendCommand(CMD_SET_SENSOR_MOCK + " " + SensorType.BatteryVoltage.ordinal() + " 12"); String msg; EngineChart chart; // todo: interesting changeRpm(100); sendComplexCommand("set cranking_rpm 500"); ecu.changeRpm(200); chart = nextChart(); EcuTestHelper.assertSomewhatClose(12, SensorCentral.getInstance().getValue(Sensor.VBATT)); assertWaveNotNull("aspire default cranking ", chart, EngineChart.SPARK_1); ecu.changeRpm(600); chart = nextChart(); assertWaveNotNull("aspire default running ", chart, EngineChart.SPARK_1); ecu.changeRpm(200); ecu.sendCommand("set cranking_charge_angle 65"); ecu.sendCommand("set cranking_timing_angle -31"); chart = nextChart(); assertWaveNotNull("aspire cranking", chart, EngineChart.SPARK_1); ecu.sendCommand("set cranking_timing_angle -40"); chart = nextChart(); assertWaveNotNull("aspire", chart, EngineChart.SPARK_1); ecu.sendCommand("set cranking_timing_angle 149"); ecu.sendCommand("set cranking_charge_angle 40"); chart = nextChart(); assertWaveNotNull("aspire", chart, EngineChart.SPARK_1); ecu.sendCommand("set cranking_charge_angle 65"); ecu.changeRpm(600); sendComplexCommand("set cranking_rpm 700"); chart = nextChart(); assertWaveNotNull("cranking@600", chart, EngineChart.SPARK_1); ecu.changeRpm(2000); ecu.changeRpm(2600); ecu.changeRpm(2000); chart = nextChart(); msg = "aspire running"; assertWaveNotNull(msg, chart, EngineChart.INJECTOR_1); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_2); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_3); assertWaveNotNull(msg, chart, EngineChart.INJECTOR_4); assertWaveNotNull(chart, EngineChart.SPARK_1); ecu.sendCommand("set_fuel_map 2200 4 15.66"); ecu.sendCommand("set_fuel_map 2000 4 15.66"); ecu.sendCommand("set_fuel_map 2200 4.2 15.66"); ecu.sendCommand("set_fuel_map 2000 4.2 15.66"); sendComplexCommand("set global_trigger_offset_angle 175"); chart = nextChart(); assertWaveNotNull(msg + " fuel", chart, EngineChart.INJECTOR_1); assertWaveNotNull(msg + " fuel", chart, EngineChart.INJECTOR_2); assertWaveNotNull(msg + " fuel", chart, EngineChart.INJECTOR_3); assertWaveNotNull(msg + " fuel", chart, EngineChart.INJECTOR_4); assertWaveNotNull(chart, EngineChart.SPARK_1); assertWaveNull(chart, EngineChart.SPARK_2); sendComplexCommand("set global_trigger_offset_angle 130"); sendComplexCommand("set injection_offset 369"); chart = nextChart(); assertWaveNotNull(chart, EngineChart.SPARK_1); // let's enable more channels dynamically sendComplexCommand(Fields.CMD_INDIVIDUAL_INJECTION); chart = nextChart(); assertWaveNotNull("Switching Aspire into INDIVIDUAL_COILS mode", chart, EngineChart.SPARK_2); assertWaveNotNull(chart, EngineChart.SPARK_3); ecu.sendCommand("set_whole_timing_map 520"); chart = nextChart(); assertWaveNotNull(chart, EngineChart.SPARK_2); // switching to Speed Density sendComplexCommand("set algorithm 0"); ecu.changeRpm(2400); ecu.changeRpm(2000); chart = nextChart(); EcuTestHelper.assertSomewhatClose("MAP", 69.12, SensorCentral.getInstance().getValue(Sensor.MAP)); //assertEquals(1, SensorCentral.getInstance().getValue(Sensor.)); assertWaveNotNull(msg + " fuel SD #1", chart, EngineChart.INJECTOR_1); assertWaveNotNull(msg + " fuel SD #2", chart, EngineChart.INJECTOR_2); assertWaveNotNull(msg + " fuel SD #3", chart, EngineChart.INJECTOR_3); assertWaveNotNull(msg + " fuel SD #4", chart, EngineChart.INJECTOR_4); // above hard limit ecu.changeRpm(10000); chart = nextChart(); assertWaveNull("hard limit check", chart, EngineChart.INJECTOR_1); } @Test public void testStackOverflow() { // This ECU command has a built in check to make sure no threads are near overflow ecu.sendCommand("threadsinfo"); } /** * This method waits for longer then usual. * todo: inline this method? complex and less complex seem to have same timeout these days? */ private void sendComplexCommand(String command) { ecu.sendCommand(command); } private static void assertWaveNull(EngineChart chart, String key) { assertWaveNull("", chart, key); } private static void assertWaveNull(EngineChart chart, String... keys) { Arrays.stream(keys).peek(k -> assertWaveNull(chart, k)); } private static void assertWaveNull(String msg, EngineChart chart, String key) { assertNull(msg + "chart for " + key, chart.get(key)); } private static void assertWaveNotNull(EngineChart chart, String key) { assertWaveNotNull("", chart, key); } private static void assertWaveNotNull(String msg, EngineChart chart, String key) { assertTrue(msg, chart.get(key) != null); } private static void assertWaveNotNull(EngineChart chart, String... keys) { Arrays.stream(keys).peek(k -> assertWaveNotNull(chart, k)); } private static void assertWaveNoRises(EngineChart chart, String key) { StringBuilder events = chart.get(key); // if no events of this type at all, return since this passes the test if (events == null) { return; } // Assert that there are no up (rise) events in the channel's sequence assertFalse(events.toString().contains("u")); } private static void assertWaveNoRises(EngineChart chart, String... keys) { Arrays.stream(keys).peek(k -> assertWaveNoRises(chart, k)); } }