diff --git a/firmware/controllers/algo/engine_configuration.cpp b/firmware/controllers/algo/engine_configuration.cpp index afd42b1827..f321d4ed9d 100644 --- a/firmware/controllers/algo/engine_configuration.cpp +++ b/firmware/controllers/algo/engine_configuration.cpp @@ -1072,6 +1072,8 @@ static void setDefaultEngineConfiguration(DECLARE_ENGINE_PARAMETER_SIGNATURE) { // set_fsio_expression 1 "rpm > fsio_setting(1)" setFsio(0, GPIO_UNASSIGNED, RPM_ABOVE_USER_SETTING_1 PASS_CONFIG_PARAMETER_SUFFIX); #endif /* EFI_FSIO */ + + strncpy(config->luaScript, "function onTick()\nend", efi::size(config->luaScript)); } /** diff --git a/firmware/controllers/algo/rusefi_types.h b/firmware/controllers/algo/rusefi_types.h index efd70cd768..9ce312812e 100644 --- a/firmware/controllers/algo/rusefi_types.h +++ b/firmware/controllers/algo/rusefi_types.h @@ -81,6 +81,8 @@ typedef float percent_t; typedef void (*Void)(void); +typedef char lua_script_t[LUA_SCRIPT_SIZE]; + typedef char error_message_t[ERROR_BUFFER_SIZE]; typedef char vehicle_info_t[VEHICLE_INFO_SIZE]; diff --git a/firmware/controllers/lua/lua.cpp b/firmware/controllers/lua/lua.cpp index daa6856ffb..24b8a15da2 100644 --- a/firmware/controllers/lua/lua.cpp +++ b/firmware/controllers/lua/lua.cpp @@ -234,9 +234,7 @@ static bool runOneLua() { // Reset default tick rate luaTickPeriodMs = 100; - auto scriptStr = "function onTick() end"; - - if (!loadScript(ls, scriptStr)) { + if (!loadScript(ls, config->luaScript)) { return false; } diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index 459aa99d9b..71a1cac11a 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -1592,8 +1592,9 @@ fsio_table_8x8_u8t vvtTable2; float[FSIO_TABLE_8] vvtTable2LoadBins;;"L", 1, 0, 0.0, 255, 0 float[FSIO_TABLE_8] vvtTable2RpmBins;RPM is float and not integer in order to use unified methods for interpolation;"RPM", 1, 0, 0.0, 25500.0, 2 - -uint8_t[256] unused15136;;"units", 1, 0, -20, 100, 0 +#define LUA_SCRIPT_SIZE 256 +custom lua_script_t @@LUA_SCRIPT_SIZE@@ string, ASCII, @OFFSET@, @@LUA_SCRIPT_SIZE@@ +lua_script_t luaScript; ignition_table_t ignitionTable; float[IGN_LOAD_COUNT] ignitionLoadBins;;"Load", 1, 0.0, 0, 500.0, 2 diff --git a/java_console/io/src/main/java/com/rusefi/binaryprotocol/BinaryProtocol.java b/java_console/io/src/main/java/com/rusefi/binaryprotocol/BinaryProtocol.java index ed6f298974..41b1a3d3ff 100644 --- a/java_console/io/src/main/java/com/rusefi/binaryprotocol/BinaryProtocol.java +++ b/java_console/io/src/main/java/com/rusefi/binaryprotocol/BinaryProtocol.java @@ -324,7 +324,7 @@ public class BinaryProtocol { byte[] newBytes = newVersion.getRange(range.first, size); log.info("new " + Arrays.toString(newBytes)); - writeData(newVersion.getContent(), range.first, size); + writeData(newVersion.getContent(), 0, range.first, size); offset = range.second; } @@ -489,15 +489,15 @@ public class BinaryProtocol { Runtime.getRuntime().removeShutdownHook(hook); } - public void writeData(byte[] content, Integer offset, int size) { + public void writeData(byte[] content, int contentOffset, int ecuOffset, int size) { isBurnPending = true; byte packet[] = new byte[5 + size]; packet[0] = Fields.TS_CHUNK_WRITE_COMMAND; - putShort(packet, 1, swap16(offset)); + putShort(packet, 1, swap16(ecuOffset)); putShort(packet, 3, swap16(size)); - System.arraycopy(content, offset, packet, 7, size); + System.arraycopy(content, contentOffset, packet, 5, size); long start = System.currentTimeMillis(); while (!isClosed && (System.currentTimeMillis() - start < Timeouts.BINARY_IO_TIMEOUT)) { diff --git a/java_console/models/src/main/java/com/rusefi/config/generated/Fields.java b/java_console/models/src/main/java/com/rusefi/config/generated/Fields.java index 5af1cf3d68..df3fc41613 100644 --- a/java_console/models/src/main/java/com/rusefi/config/generated/Fields.java +++ b/java_console/models/src/main/java/com/rusefi/config/generated/Fields.java @@ -1,6 +1,6 @@ package com.rusefi.config.generated; -// this file was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Mon May 17 09:41:25 UTC 2021 +// this file was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh integration/rusefi_config.txt Mon May 17 14:39:09 PDT 2021 // by class com.rusefi.output.FileJavaFieldsConsumer import com.rusefi.config.*; @@ -1036,6 +1036,8 @@ public class Fields { public static final int lowPressureFuel_value2_offset = 3324; public static final int lps25BaroSensorScl_offset = 1458; public static final int lps25BaroSensorSda_offset = 1459; + public static final int LUA_SCRIPT_SIZE = 256; + public static final int luaScript_offset = 16032; public static final int MAF_DECODING_COUNT = 256; public static final int mafAdcChannel_offset = 543; public static final int mafDecoding_offset = 10784; @@ -1210,7 +1212,7 @@ public class Fields { public static final int servoOutputPins8_offset = 3147; public static final int showHumanReadableWarning_offset = 976; public static final int showSdCardWarning_offset = 76; - public static final int SIGNATURE_HASH = 1539247760; + public static final int SIGNATURE_HASH = 1304382715; public static final int silentTriggerError_offset = 1464; public static final int slowAdcAlpha_offset = 2088; public static final int sparkDwellRpmBins_offset = 332; @@ -1494,7 +1496,7 @@ public class Fields { public static final char TS_SD_R_COMMAND = 'r'; public static final char TS_SD_W_COMMAND = 'w'; public static final char TS_SET_LOGGER_SWITCH = 'l'; - public static final String TS_SIGNATURE = "rusEFI 2021.05.17.all.1539247760"; + public static final String TS_SIGNATURE = "rusEFI 2021.05.17.all.1304382715"; public static final char TS_SINGLE_WRITE_COMMAND = 'W'; public static final int TT_TT_1_16 = 50; public static final int TT_TT_2JZ_1_12 = 29; @@ -1556,7 +1558,6 @@ public class Fields { public static final int unused1476b20_offset = 1476; public static final int unused1476b3_offset = 1476; public static final int unused1476b8_offset = 1476; - public static final int unused15136_offset = 16032; public static final int unused1708_offset = 1708; public static final int unused1756_offset = 1756; public static final int unused2260_offset = 2260; @@ -2781,6 +2782,7 @@ public class Fields { public static final Field MAPESTIMATETABLE = Field.create("MAPESTIMATETABLE", 15200, FieldType.INT); public static final Field VVTTABLE1 = Field.create("VVTTABLE1", 15776, FieldType.INT); public static final Field VVTTABLE2 = Field.create("VVTTABLE2", 15904, FieldType.INT); + public static final Field LUASCRIPT = Field.create("LUASCRIPT", 16032, 256, FieldType.STRING); public static final Field IGNITIONTABLE = Field.create("IGNITIONTABLE", 16288, FieldType.INT); public static final Field VETABLE = Field.create("VETABLE", 17440, FieldType.INT); public static final Field LAMBDATABLE = Field.create("LAMBDATABLE", 18592, FieldType.INT); @@ -3844,6 +3846,7 @@ public class Fields { MAPESTIMATETABLE, VVTTABLE1, VVTTABLE2, + LUASCRIPT, IGNITIONTABLE, VETABLE, LAMBDATABLE, diff --git a/java_console/ui/src/main/java/com/rusefi/ConsoleUI.java b/java_console/ui/src/main/java/com/rusefi/ConsoleUI.java index 8da744f40c..55ea34e872 100644 --- a/java_console/ui/src/main/java/com/rusefi/ConsoleUI.java +++ b/java_console/ui/src/main/java/com/rusefi/ConsoleUI.java @@ -17,6 +17,7 @@ import com.rusefi.ui.console.MainFrame; import com.rusefi.ui.console.TabbedPanel; import com.rusefi.ui.engine.EngineSnifferPanel; import com.rusefi.ui.logview.LogViewer; +import com.rusefi.ui.lua.LuaScriptPanel; import com.rusefi.ui.util.DefaultExceptionHandler; import com.rusefi.ui.util.JustOneInstance; @@ -108,6 +109,11 @@ public class ConsoleUI { tabbedPane.addTab("Presets", new PresetsPane(uiContext).getContent()); } + if (!linkManager.isLogViewer()) { + LuaScriptPanel luaScriptPanel = new LuaScriptPanel(uiContext, getConfig().getRoot().getChild("lua")); + tabbedPaneAdd("Lua Scripting", luaScriptPanel.getPanel(), luaScriptPanel.getTabSelectedListener()); + } + tabbedPaneAdd("Engine Sniffer", engineSnifferPanel.getPanel(), engineSnifferPanel.getTabSelectedListener()); if (!linkManager.isLogViewer()) { diff --git a/java_console/ui/src/main/java/com/rusefi/ui/lua/LuaScriptPanel.java b/java_console/ui/src/main/java/com/rusefi/ui/lua/LuaScriptPanel.java new file mode 100644 index 0000000000..875cd22780 --- /dev/null +++ b/java_console/ui/src/main/java/com/rusefi/ui/lua/LuaScriptPanel.java @@ -0,0 +1,132 @@ +package com.rusefi.ui.lua; + +import com.opensr5.ConfigurationImage; +import com.rusefi.FixedCommandControl; +import com.rusefi.binaryprotocol.BinaryProtocol; +import com.rusefi.config.generated.Fields; +import com.rusefi.ui.MessagesPanel; +import com.rusefi.ui.UIContext; +import com.rusefi.ui.storage.Node; +import com.rusefi.ui.widgets.AnyCommand; + +import javax.swing.*; +import javax.swing.border.Border; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +public class LuaScriptPanel { + private final UIContext context; + private final JPanel mainPanel = new JPanel(new BorderLayout()); + private final AnyCommand command; + private final JTextArea scriptText; + + public LuaScriptPanel(UIContext context, Node config) { + this.context = context; + this.command = AnyCommand.createField(context, config, true, true); + + // Upper panel: command entry, etc + JPanel upperPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0)); + + JButton readButton = new JButton("Read from ECU"); + JButton writeButton = new JButton("Write to ECU"); + JButton resetButton = new JButton("Reset/Reload Lua"); + + readButton.addActionListener(e -> read()); + writeButton.addActionListener(e -> write()); + resetButton.addActionListener(e -> resetLua()); + + upperPanel.add(readButton); + upperPanel.add(writeButton); + upperPanel.add(resetButton); + upperPanel.add(this.command.getContent()); + + // Center panel - script editor and log + JPanel scriptPanel = new JPanel(new BorderLayout()); + this.scriptText = new JTextArea(); + this.scriptText.setTabSize(2); + scriptPanel.add(this.scriptText, BorderLayout.CENTER); + + //centerPanel.add(, BorderLayout.WEST); + JPanel messagesPanel = new JPanel(new BorderLayout()); + MessagesPanel mp = new MessagesPanel(null); + messagesPanel.add(BorderLayout.NORTH, mp.getButtonPanel()); + messagesPanel.add(BorderLayout.CENTER, mp.getMessagesScroll()); + + JSplitPane centerPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scriptPanel, messagesPanel); + + this.mainPanel.add(upperPanel, BorderLayout.NORTH); + this.mainPanel.add(centerPanel, BorderLayout.CENTER); + } + + public JPanel getPanel() { + return mainPanel; + } + + public ActionListener getTabSelectedListener() { + return new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (command != null) + command.requestFocus(); + } + }; + } + + void read() { + BinaryProtocol bp = this.context.getLinkManager().getCurrentStreamState(); + + if (bp == null) { + // TODO: Handle missing ECU + return; + } + + ConfigurationImage image = bp.getControllerConfiguration(); + ByteBuffer luaScriptBuffer = image.getByteBuffer(Fields.luaScript_offset, Fields.LUA_SCRIPT_SIZE); + + byte scriptArr[] = new byte[Fields.LUA_SCRIPT_SIZE]; + luaScriptBuffer.get(scriptArr); + + int i; + // Find the null terminator + for (i = 0; i < scriptArr.length && scriptArr[i] != 0; i++) ; + scriptText.setText(new String(scriptArr, 0, i, Charset.forName("ASCII"))); + } + + void write() { + BinaryProtocol bp = this.context.getLinkManager().getCurrentStreamState(); + + String script = scriptText.getText(); + + byte paddedScript[] = new byte[Fields.LUA_SCRIPT_SIZE]; + byte scriptBytes[] = script.getBytes(StandardCharsets.US_ASCII); + System.arraycopy(scriptBytes, 0, paddedScript, 0, scriptBytes.length); + + int idx = 0; + int remaining; + + do { + remaining = paddedScript.length - idx; + int thisWrite = remaining > Fields.BLOCKING_FACTOR ? Fields.BLOCKING_FACTOR : remaining; + + bp.writeData(paddedScript, idx, Fields.luaScript_offset + idx, thisWrite); + + idx += thisWrite; + + remaining -= thisWrite; + } while (remaining > 0); + + bp.burn(); + + // Burning doesn't reload lua script, so we have to do it manually + resetLua(); + } + + void resetLua() { + this.context.getCommandQueue().write("luareset"); + } +}