AP_Scripting: Add support for REPL over MAVLink

This commit is contained in:
Michael du Breuil
2020-02-05 15:58:33 -07:00
committed by WickedShell
parent 296c014d14
commit cf06beb1e6
5 changed files with 406 additions and 16 deletions

View File

@@ -33,9 +33,10 @@ extern const AP_HAL::HAL& hal;
bool lua_scripts::overtime;
jmp_buf lua_scripts::panic_jmp;
lua_scripts::lua_scripts(const AP_Int32 &vm_steps, const AP_Int32 &heap_size, const AP_Int8 &debug_level)
lua_scripts::lua_scripts(const AP_Int32 &vm_steps, const AP_Int32 &heap_size, const AP_Int8 &debug_level, struct AP_Scripting::terminal_s &_terminal)
: _vm_steps(vm_steps),
_debug_level(debug_level) {
_debug_level(debug_level),
terminal(_terminal) {
_heap = hal.util->allocate_heap_memory(heap_size);
}
@@ -52,6 +53,7 @@ void lua_scripts::hook(lua_State *L, lua_Debug *ar) {
int lua_scripts::atpanic(lua_State *L) {
gcs().send_text(MAV_SEVERITY_CRITICAL, "Lua: Panic: %s", lua_tostring(L, -1));
hal.console->printf("Lua: Panic: %s\n", lua_tostring(L, -1));
printf("Lua: Panic: %s\n", lua_tostring(L, -1));
longjmp(panic_jmp, 1);
return 0;
}
@@ -91,8 +93,16 @@ lua_scripts::script_info *lua_scripts::load_script(lua_State *L, char *filename)
new_script->name = filename;
new_script->next = nullptr;
create_sandbox(L);
lua_setupvalue(L, -2, 1);
// find and create a sandbox for the new chunk
new_script->lua_ref = luaL_ref(L, LUA_REGISTRYINDEX); // cache the reference
new_script->next_run_ms = AP_HAL::millis64() - 1; // force the script to be stale
return new_script;
}
void lua_scripts::create_sandbox(lua_State *L) {
lua_newtable(L);
luaopen_base_sandbox(L);
lua_pushstring(L, "math");
@@ -112,12 +122,7 @@ lua_scripts::script_info *lua_scripts::load_script(lua_State *L, char *filename)
lua_settable(L, -3);
load_lua_bindings(L);
load_generated_sandbox(L);
lua_setupvalue(L, -2, 1);
new_script->lua_ref = luaL_ref(L, LUA_REGISTRYINDEX); // cache the reference
new_script->next_run_ms = AP_HAL::millis64() - 1; // force the script to be stale
return new_script;
}
void lua_scripts::load_all_scripts_in_dir(lua_State *L, const char *dirname) {
@@ -164,6 +169,13 @@ void lua_scripts::load_all_scripts_in_dir(lua_State *L, const char *dirname) {
AP::FS().closedir(d);
}
void lua_scripts::reset_loop_overtime(lua_State *L) {
overtime = false;
// reset the hook to clear the counter
const int32_t vm_steps = MAX(_vm_steps, 1000);
lua_sethook(L, hook, LUA_MASKCOUNT, vm_steps);
}
void lua_scripts::run_next_script(lua_State *L) {
if (scripts == nullptr) {
#if defined(AP_SCRIPTING_CHECKS) && AP_SCRIPTING_CHECKS >= 1
@@ -172,16 +184,12 @@ void lua_scripts::run_next_script(lua_State *L) {
return;
}
// reset the current script tracking information
overtime = false;
// strip the selected script out of the list
script_info *script = scripts;
scripts = script->next;
// reset the hook to clear the counter
const int32_t vm_steps = MAX(_vm_steps, 1000);
lua_sethook(L, hook, LUA_MASKCOUNT, vm_steps);
reset_loop_overtime(L);
// store top of stack so we can calculate the number of return values
int stack_top = lua_gettop(L);
@@ -192,7 +200,7 @@ void lua_scripts::run_next_script(lua_State *L) {
if(lua_pcall(L, 0, LUA_MULTRET, 0)) {
if (overtime) {
// script has consumed an excessive amount of CPU time
gcs().send_text(MAV_SEVERITY_CRITICAL, "Lua: %s exceeded time limit (%d)", script->name, (int)vm_steps);
gcs().send_text(MAV_SEVERITY_CRITICAL, "Lua: %s exceeded time limit", script->name);
remove_script(L, script);
} else {
hal.console->printf("Lua: Error: %s\n", lua_tostring(L, -1));
@@ -314,6 +322,19 @@ void *lua_scripts::alloc(void *ud, void *ptr, size_t osize, size_t nsize) {
return hal.util->heap_realloc(_heap, ptr, nsize);
}
void lua_scripts::repl_cleanup (void) {
if (terminal.session) {
terminal.session = false;
if (terminal.output_fd != -1) {
AP::FS().close(terminal.output_fd);
terminal.output_fd = -1;
AP::FS().unlink(REPL_DIRECTORY "/in");
AP::FS().unlink(REPL_DIRECTORY "/out");
AP::FS().unlink(REPL_DIRECTORY);
}
}
}
void lua_scripts::run(void) {
bool succeeded_initial_load = false;
@@ -336,6 +357,8 @@ void lua_scripts::run(void) {
}
scripts = nullptr;
overtime = false;
// end any open REPL sessions
repl_cleanup();
}
lua_state = lua_newstate(alloc, NULL);
@@ -355,6 +378,12 @@ void lua_scripts::run(void) {
succeeded_initial_load = true;
while (AP_Scripting::get_singleton()->enabled()) {
// handle terminal data if we have any
if (terminal.session) {
doREPL(L);
continue;
}
#if defined(AP_SCRIPTING_CHECKS) && AP_SCRIPTING_CHECKS >= 1
if (lua_gettop(L) != 0) {
AP_HAL::panic("Lua: Stack should be empty before running scripts");