Lua script editor in console (#2699)

* stub

* implement reset

* console

* just use the console command

* cleanup

* s

* s

* ui

* write in chunks

* fix write

* tab size, script read

* parse script properly

* put lua script in flash, tiny for now

* generated fields
This commit is contained in:
Matthew Kennedy 2021-05-18 10:58:39 -07:00 committed by GitHub
parent ca1812ee51
commit 6d9c0299fb
7 changed files with 150 additions and 9 deletions

View File

@ -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));
}
/**

View File

@ -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];

View File

@ -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;
}

View File

@ -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

View File

@ -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)) {

View File

@ -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()) {

View File

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