[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 11:54:32 +03:00
|
|
|
#include <common/cs_dbg.h>
|
2024-10-31 05:22:05 +00:00
|
|
|
#include <toolbox/path.h>
|
[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 11:54:32 +03:00
|
|
|
#include <toolbox/stream/file_stream.h>
|
2024-10-31 05:22:05 +00:00
|
|
|
#include <toolbox/strint.h>
|
[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 11:54:32 +03:00
|
|
|
#include <loader/firmware_api/firmware_api.h>
|
|
|
|
|
#include <flipper_application/api_hashtable/api_hashtable.h>
|
|
|
|
|
#include <flipper_application/plugins/composite_resolver.h>
|
|
|
|
|
#include <furi_hal.h>
|
|
|
|
|
#include "plugin_api/app_api_interface.h"
|
|
|
|
|
#include "js_thread.h"
|
|
|
|
|
#include "js_thread_i.h"
|
|
|
|
|
#include "js_modules.h"
|
|
|
|
|
|
|
|
|
|
#define TAG "JS"
|
|
|
|
|
|
|
|
|
|
struct JsThread {
|
|
|
|
|
FuriThread* thread;
|
|
|
|
|
FuriString* path;
|
|
|
|
|
CompositeApiResolver* resolver;
|
|
|
|
|
JsThreadCallback app_callback;
|
|
|
|
|
void* context;
|
|
|
|
|
JsModules* modules;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void js_str_print(FuriString* msg_str, struct mjs* mjs) {
|
|
|
|
|
size_t num_args = mjs_nargs(mjs);
|
|
|
|
|
for(size_t i = 0; i < num_args; i++) {
|
|
|
|
|
char* name = NULL;
|
|
|
|
|
size_t name_len = 0;
|
|
|
|
|
int need_free = 0;
|
|
|
|
|
mjs_val_t arg = mjs_arg(mjs, i);
|
|
|
|
|
mjs_err_t err = mjs_to_string(mjs, &arg, &name, &name_len, &need_free);
|
|
|
|
|
if(err != MJS_OK) {
|
|
|
|
|
furi_string_cat_printf(msg_str, "err %s ", mjs_strerror(mjs, err));
|
|
|
|
|
} else {
|
|
|
|
|
furi_string_cat_printf(msg_str, "%s ", name);
|
|
|
|
|
}
|
|
|
|
|
if(need_free) {
|
|
|
|
|
free(name);
|
|
|
|
|
name = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void js_print(struct mjs* mjs) {
|
|
|
|
|
FuriString* msg_str = furi_string_alloc();
|
|
|
|
|
js_str_print(msg_str, mjs);
|
|
|
|
|
|
|
|
|
|
JsThread* worker = mjs_get_context(mjs);
|
|
|
|
|
furi_assert(worker);
|
|
|
|
|
if(worker->app_callback) {
|
|
|
|
|
worker->app_callback(JsThreadEventPrint, furi_string_get_cstr(msg_str), worker->context);
|
2024-03-25 19:35:38 +03:00
|
|
|
} else {
|
|
|
|
|
FURI_LOG_D(TAG, "%s\r\n", furi_string_get_cstr(msg_str));
|
[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 11:54:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
furi_string_free(msg_str);
|
|
|
|
|
|
|
|
|
|
mjs_return(mjs, MJS_UNDEFINED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void js_console_log(struct mjs* mjs) {
|
|
|
|
|
FuriString* msg_str = furi_string_alloc();
|
|
|
|
|
js_str_print(msg_str, mjs);
|
|
|
|
|
FURI_LOG_I(TAG, "%s", furi_string_get_cstr(msg_str));
|
|
|
|
|
furi_string_free(msg_str);
|
|
|
|
|
mjs_return(mjs, MJS_UNDEFINED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void js_console_warn(struct mjs* mjs) {
|
|
|
|
|
FuriString* msg_str = furi_string_alloc();
|
|
|
|
|
js_str_print(msg_str, mjs);
|
|
|
|
|
FURI_LOG_W(TAG, "%s", furi_string_get_cstr(msg_str));
|
|
|
|
|
furi_string_free(msg_str);
|
|
|
|
|
mjs_return(mjs, MJS_UNDEFINED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void js_console_error(struct mjs* mjs) {
|
|
|
|
|
FuriString* msg_str = furi_string_alloc();
|
|
|
|
|
js_str_print(msg_str, mjs);
|
|
|
|
|
FURI_LOG_E(TAG, "%s", furi_string_get_cstr(msg_str));
|
|
|
|
|
furi_string_free(msg_str);
|
|
|
|
|
mjs_return(mjs, MJS_UNDEFINED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void js_console_debug(struct mjs* mjs) {
|
|
|
|
|
FuriString* msg_str = furi_string_alloc();
|
|
|
|
|
js_str_print(msg_str, mjs);
|
|
|
|
|
FURI_LOG_D(TAG, "%s", furi_string_get_cstr(msg_str));
|
|
|
|
|
furi_string_free(msg_str);
|
|
|
|
|
mjs_return(mjs, MJS_UNDEFINED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void js_exit_flag_poll(struct mjs* mjs) {
|
|
|
|
|
uint32_t flags = furi_thread_flags_wait(ThreadEventStop, FuriFlagWaitAny, 0);
|
|
|
|
|
if(flags & FuriFlagError) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(flags & ThreadEventStop) {
|
|
|
|
|
mjs_exit(mjs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool js_delay_with_flags(struct mjs* mjs, uint32_t time) {
|
|
|
|
|
uint32_t flags = furi_thread_flags_wait(ThreadEventStop, FuriFlagWaitAny, time);
|
|
|
|
|
if(flags & FuriFlagError) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if(flags & ThreadEventStop) {
|
|
|
|
|
mjs_exit(mjs);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void js_flags_set(struct mjs* mjs, uint32_t flags) {
|
|
|
|
|
JsThread* worker = mjs_get_context(mjs);
|
|
|
|
|
furi_assert(worker);
|
|
|
|
|
furi_thread_flags_set(furi_thread_get_id(worker->thread), flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t js_flags_wait(struct mjs* mjs, uint32_t flags_mask, uint32_t timeout) {
|
|
|
|
|
flags_mask |= ThreadEventStop;
|
|
|
|
|
uint32_t flags = furi_thread_flags_get();
|
|
|
|
|
furi_check((flags & FuriFlagError) == 0);
|
|
|
|
|
if(flags == 0) {
|
|
|
|
|
flags = furi_thread_flags_wait(flags_mask, FuriFlagWaitAny, timeout);
|
|
|
|
|
} else {
|
|
|
|
|
uint32_t state = furi_thread_flags_clear(flags & flags_mask);
|
|
|
|
|
furi_check((state & FuriFlagError) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(flags & FuriFlagError) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if(flags & ThreadEventStop) {
|
|
|
|
|
mjs_exit(mjs);
|
|
|
|
|
}
|
|
|
|
|
return flags;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void js_delay(struct mjs* mjs) {
|
|
|
|
|
bool args_correct = false;
|
|
|
|
|
int ms = 0;
|
|
|
|
|
|
|
|
|
|
if(mjs_nargs(mjs) == 1) {
|
|
|
|
|
mjs_val_t arg = mjs_arg(mjs, 0);
|
|
|
|
|
if(mjs_is_number(arg)) {
|
|
|
|
|
ms = mjs_get_int(mjs, arg);
|
|
|
|
|
args_correct = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(!args_correct) {
|
|
|
|
|
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "");
|
|
|
|
|
mjs_return(mjs, MJS_UNDEFINED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
js_delay_with_flags(mjs, ms);
|
|
|
|
|
mjs_return(mjs, MJS_UNDEFINED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void* js_dlsym(void* handle, const char* name) {
|
|
|
|
|
CompositeApiResolver* resolver = handle;
|
|
|
|
|
Elf32_Addr addr = 0;
|
|
|
|
|
uint32_t hash = elf_symbolname_hash(name);
|
|
|
|
|
const ElfApiInterface* api = composite_api_resolver_get(resolver);
|
|
|
|
|
|
|
|
|
|
if(!api->resolver_callback(api, hash, &addr)) {
|
|
|
|
|
FURI_LOG_E(TAG, "FFI: cannot find \"%s\"", name);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (void*)addr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void js_ffi_address(struct mjs* mjs) {
|
|
|
|
|
mjs_val_t name_v = mjs_arg(mjs, 0);
|
|
|
|
|
size_t len;
|
|
|
|
|
const char* name = mjs_get_string(mjs, &name_v, &len);
|
|
|
|
|
void* addr = mjs_ffi_resolve(mjs, name);
|
|
|
|
|
mjs_return(mjs, mjs_mk_foreign(mjs, addr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void js_require(struct mjs* mjs) {
|
|
|
|
|
mjs_val_t name_v = mjs_arg(mjs, 0);
|
|
|
|
|
size_t len;
|
|
|
|
|
const char* name = mjs_get_string(mjs, &name_v, &len);
|
|
|
|
|
mjs_val_t req_object = MJS_UNDEFINED;
|
|
|
|
|
if((len == 0) || (name == NULL)) {
|
|
|
|
|
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "String argument is expected");
|
|
|
|
|
} else {
|
|
|
|
|
JsThread* worker = mjs_get_context(mjs);
|
|
|
|
|
furi_assert(worker);
|
|
|
|
|
req_object = js_module_require(worker->modules, name, len);
|
|
|
|
|
}
|
|
|
|
|
mjs_return(mjs, req_object);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-31 05:22:05 +00:00
|
|
|
static void js_parse_int(struct mjs* mjs) {
|
|
|
|
|
const char* str;
|
|
|
|
|
JS_FETCH_ARGS_OR_RETURN(mjs, JS_AT_LEAST, JS_ARG_STR(&str));
|
|
|
|
|
|
|
|
|
|
int32_t base = 10;
|
|
|
|
|
if(mjs_nargs(mjs) >= 2) {
|
|
|
|
|
mjs_val_t base_arg = mjs_arg(mjs, 1);
|
|
|
|
|
if(!mjs_is_number(base_arg)) {
|
|
|
|
|
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Base must be a number");
|
|
|
|
|
mjs_return(mjs, MJS_UNDEFINED);
|
|
|
|
|
}
|
|
|
|
|
base = mjs_get_int(mjs, base_arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t num;
|
|
|
|
|
if(strint_to_int32(str, NULL, &num, base) != StrintParseNoError) {
|
|
|
|
|
num = 0;
|
|
|
|
|
}
|
|
|
|
|
mjs_return(mjs, mjs_mk_number(mjs, num));
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-14 06:14:29 +03:00
|
|
|
#ifdef JS_DEBUG
|
[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 11:54:32 +03:00
|
|
|
static void js_dump_write_callback(void* ctx, const char* format, ...) {
|
|
|
|
|
File* file = ctx;
|
|
|
|
|
furi_assert(ctx);
|
|
|
|
|
|
|
|
|
|
FuriString* str = furi_string_alloc();
|
|
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
|
va_start(args, format);
|
|
|
|
|
furi_string_vprintf(str, format, args);
|
|
|
|
|
furi_string_cat(str, "\n");
|
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
|
|
storage_file_write(file, furi_string_get_cstr(str), furi_string_size(str));
|
|
|
|
|
furi_string_free(str);
|
|
|
|
|
}
|
2024-02-14 06:14:29 +03:00
|
|
|
#endif
|
[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 11:54:32 +03:00
|
|
|
|
|
|
|
|
static int32_t js_thread(void* arg) {
|
|
|
|
|
JsThread* worker = arg;
|
|
|
|
|
worker->resolver = composite_api_resolver_alloc();
|
|
|
|
|
composite_api_resolver_add(worker->resolver, firmware_api_interface);
|
|
|
|
|
composite_api_resolver_add(worker->resolver, application_api_interface);
|
|
|
|
|
|
|
|
|
|
struct mjs* mjs = mjs_create(worker);
|
|
|
|
|
worker->modules = js_modules_create(mjs, worker->resolver);
|
|
|
|
|
mjs_val_t global = mjs_get_global(mjs);
|
|
|
|
|
mjs_val_t console_obj = mjs_mk_object(mjs);
|
2024-10-31 05:42:57 +03:00
|
|
|
|
2024-10-31 05:22:05 +00:00
|
|
|
if(worker->path) {
|
|
|
|
|
FuriString* dirpath = furi_string_alloc();
|
|
|
|
|
path_extract_dirname(furi_string_get_cstr(worker->path), dirpath);
|
|
|
|
|
mjs_set(
|
|
|
|
|
mjs,
|
|
|
|
|
global,
|
|
|
|
|
"__filename",
|
|
|
|
|
~0,
|
|
|
|
|
mjs_mk_string(
|
|
|
|
|
mjs, furi_string_get_cstr(worker->path), furi_string_size(worker->path), true));
|
|
|
|
|
mjs_set(
|
|
|
|
|
mjs,
|
|
|
|
|
global,
|
|
|
|
|
"__dirname",
|
|
|
|
|
~0,
|
|
|
|
|
mjs_mk_string(mjs, furi_string_get_cstr(dirpath), furi_string_size(dirpath), true));
|
|
|
|
|
furi_string_free(dirpath);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-31 05:42:57 +03:00
|
|
|
JS_ASSIGN_MULTI(mjs, global) {
|
|
|
|
|
JS_FIELD("print", MJS_MK_FN(js_print));
|
|
|
|
|
JS_FIELD("delay", MJS_MK_FN(js_delay));
|
2024-10-31 05:22:05 +00:00
|
|
|
JS_FIELD("parseInt", MJS_MK_FN(js_parse_int));
|
2024-10-31 05:42:57 +03:00
|
|
|
JS_FIELD("ffi_address", MJS_MK_FN(js_ffi_address));
|
|
|
|
|
JS_FIELD("require", MJS_MK_FN(js_require));
|
|
|
|
|
JS_FIELD("console", console_obj);
|
|
|
|
|
|
|
|
|
|
JS_FIELD("sdkCompatibilityStatus", MJS_MK_FN(js_sdk_compatibility_status));
|
|
|
|
|
JS_FIELD("isSdkCompatible", MJS_MK_FN(js_is_sdk_compatible));
|
|
|
|
|
JS_FIELD("checkSdkCompatibility", MJS_MK_FN(js_check_sdk_compatibility));
|
|
|
|
|
JS_FIELD("doesSdkSupport", MJS_MK_FN(js_does_sdk_support));
|
|
|
|
|
JS_FIELD("checkSdkFeatures", MJS_MK_FN(js_check_sdk_features));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JS_ASSIGN_MULTI(mjs, console_obj) {
|
|
|
|
|
JS_FIELD("log", MJS_MK_FN(js_console_log));
|
|
|
|
|
JS_FIELD("warn", MJS_MK_FN(js_console_warn));
|
|
|
|
|
JS_FIELD("error", MJS_MK_FN(js_console_error));
|
|
|
|
|
JS_FIELD("debug", MJS_MK_FN(js_console_debug));
|
|
|
|
|
}
|
[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 11:54:32 +03:00
|
|
|
|
|
|
|
|
mjs_set_ffi_resolver(mjs, js_dlsym, worker->resolver);
|
|
|
|
|
|
|
|
|
|
mjs_set_exec_flags_poller(mjs, js_exit_flag_poll);
|
|
|
|
|
|
|
|
|
|
mjs_err_t err = mjs_exec_file(mjs, furi_string_get_cstr(worker->path), NULL);
|
|
|
|
|
|
2024-02-14 06:14:29 +03:00
|
|
|
#ifdef JS_DEBUG
|
[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 11:54:32 +03:00
|
|
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
|
|
|
|
FuriString* dump_path = furi_string_alloc_set(worker->path);
|
|
|
|
|
furi_string_cat(dump_path, ".lst");
|
|
|
|
|
|
|
|
|
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
|
|
|
|
File* file = storage_file_alloc(storage);
|
|
|
|
|
|
|
|
|
|
if(storage_file_open(
|
|
|
|
|
file, furi_string_get_cstr(dump_path), FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
|
|
|
|
mjs_disasm_all(mjs, js_dump_write_callback, file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
storage_file_close(file);
|
|
|
|
|
storage_file_free(file);
|
|
|
|
|
furi_record_close(RECORD_STORAGE);
|
|
|
|
|
|
|
|
|
|
furi_string_free(dump_path);
|
|
|
|
|
}
|
2024-02-14 06:14:29 +03:00
|
|
|
#endif
|
[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 11:54:32 +03:00
|
|
|
|
|
|
|
|
if(err != MJS_OK) {
|
|
|
|
|
FURI_LOG_E(TAG, "Exec error: %s", mjs_strerror(mjs, err));
|
|
|
|
|
if(worker->app_callback) {
|
|
|
|
|
worker->app_callback(JsThreadEventError, mjs_strerror(mjs, err), worker->context);
|
|
|
|
|
}
|
|
|
|
|
const char* stack_trace = mjs_get_stack_trace(mjs);
|
|
|
|
|
if(stack_trace != NULL) {
|
2024-05-17 17:45:40 +01:00
|
|
|
FURI_LOG_E(TAG, "Stack trace:\r\n%s", stack_trace);
|
[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 11:54:32 +03:00
|
|
|
if(worker->app_callback) {
|
|
|
|
|
worker->app_callback(JsThreadEventErrorTrace, stack_trace, worker->context);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if(worker->app_callback) {
|
|
|
|
|
worker->app_callback(JsThreadEventDone, NULL, worker->context);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mjs_destroy(mjs);
|
[FL-3893] JS modules (#3841)
* feat: backport js_gpio from unleashed
* feat: backport js_keyboard, TextInputModel::minimum_length from unleashed
* fix: api version inconsistency
* style: js_gpio
* build: fix submodule ._ .
* refactor: js_gpio
* docs: type declarations for gpio
* feat: gpio interrupts
* fix: js_gpio freeing, resetting and minor stylistic changes
* style: js_gpio
* style: mlib array, fixme's
* feat: js_gpio adc
* feat: js_event_loop
* docs: js_event_loop
* feat: js_event_loop subscription cancellation
* feat: js_event_loop + js_gpio integration
* fix: js_event_loop memory leak
* feat: stop event loop on back button
* test: js: basic, math, event_loop
* feat: js_event_loop queue
* feat: js linkage to previously loaded plugins
* build: fix ci errors
* feat: js module ordered teardown
* feat: js_gui_defer_free
* feat: basic hourglass view
* style: JS ASS (Argument Schema for Scripts)
* fix: js_event_loop mem leaks and lifetime problems
* fix: crashing test and pvs false positives
* feat: mjs custom obj destructors, gui submenu view
* refactor: yank js_gui_defer_free (yuck)
* refactor: maybe_unsubscribe
* empty_screen, docs, typing fix-ups
* docs: navigation event & demo
* feat: submenu setHeader
* feat: text_input
* feat: text_box
* docs: text_box availability
* ci: silence irrelevant pvs low priority warning
* style: use furistring
* style: _get_at -> _safe_get
* fix: built-in module name assignment
* feat: js_dialog; refactor, optimize: js_gui
* docs: js_gui
* ci: silence pvs warning: Memory allocation is infallible
* style: fix storage spelling
* feat: foreign pointer signature checks
* feat: js_storage
* docs: js_storage
* fix: my unit test was breaking other tests ;_;
* ci: fix ci?
* Make doxygen happy
* docs: flipper, math, notification, global
* style: review suggestions
* style: review fixups
* fix: badusb demo script
* docs: badusb
* ci: add nofl
* ci: make linter happy
* Bump api version
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-10-14 21:42:11 +03:00
|
|
|
js_modules_destroy(worker->modules);
|
[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 11:54:32 +03:00
|
|
|
|
|
|
|
|
composite_api_resolver_free(worker->resolver);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JsThread* js_thread_run(const char* script_path, JsThreadCallback callback, void* context) {
|
|
|
|
|
JsThread* worker = malloc(sizeof(JsThread)); //-V799
|
|
|
|
|
worker->path = furi_string_alloc_set(script_path);
|
|
|
|
|
worker->thread = furi_thread_alloc_ex("JsThread", 8 * 1024, js_thread, worker);
|
|
|
|
|
worker->app_callback = callback;
|
|
|
|
|
worker->context = context;
|
|
|
|
|
furi_thread_start(worker->thread);
|
|
|
|
|
return worker;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void js_thread_stop(JsThread* worker) {
|
|
|
|
|
furi_thread_flags_set(furi_thread_get_id(worker->thread), ThreadEventStop);
|
|
|
|
|
furi_thread_join(worker->thread);
|
|
|
|
|
furi_thread_free(worker->thread);
|
|
|
|
|
furi_string_free(worker->path);
|
|
|
|
|
free(worker);
|
|
|
|
|
}
|