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/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"); + } +}