Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
22c638b
FBT: cdefines to env, libs order
DrZlo13 Sep 15, 2023
5ce03c5
API: strtod, modf, itoa, calloc
DrZlo13 Sep 15, 2023
a57c730
Apps: elk js
DrZlo13 Sep 15, 2023
58781b5
Apps: mjs
DrZlo13 Sep 15, 2023
15be27b
JS: scripts as assets
DrZlo13 Sep 15, 2023
5b76559
mjs: composite resolver
DrZlo13 Sep 15, 2023
6130d31
mjs: stack trace
DrZlo13 Sep 15, 2023
e2c817e
ELK JS example removed
nminaylov Sep 19, 2023
f032aa2
MJS thread, MJS lib modified to support script interruption
nminaylov Sep 25, 2023
c49334f
JS console UI
nminaylov Oct 4, 2023
f972937
Module system, BadUSB bindings rework
nminaylov Oct 6, 2023
5e58b0a
JS notifications, simple dialog, BadUSB demo
nminaylov Oct 10, 2023
7cec4e8
Custom dialogs, dialog demo
nminaylov Oct 13, 2023
a6791dc
MJS as system library, some dirty hacks to make it compile
nminaylov Oct 17, 2023
573d912
Plugin-based js modules
nminaylov Oct 18, 2023
2d3e23d
Merge branch 'dev' into private/nm/js_app
nminaylov Oct 18, 2023
a8f3dca
js_uart(BadUART) module
nminaylov Oct 27, 2023
49920a7
js_uart: support for byte array arguments
nminaylov Oct 30, 2023
7032c90
Script icon and various fixes
nminaylov Nov 3, 2023
ad0b1b9
Merge branch 'dev' into private/nm/js_app
nminaylov Nov 13, 2023
9823d52
File browser: multiple extensions filter, running js scripts from app…
nminaylov Nov 22, 2023
7c1ad35
Running js scripts from archive browser
nminaylov Nov 22, 2023
22d9d1a
JS Runner as system app
nminaylov Nov 24, 2023
584f0d8
Merge branch 'dev' into private/nm/js_app
nminaylov Nov 24, 2023
96e33c2
Example scripts moved to /ext/apps/Scripts
nminaylov Nov 24, 2023
6be0df3
JS bytecode listing generation
nminaylov Nov 27, 2023
3e30df2
MJS builtin printf cleanup
nminaylov Dec 12, 2023
973467e
JS examples cleanup
nminaylov Dec 12, 2023
bb827fb
Merge branch 'dev' into nm/js_runner
nminaylov Dec 12, 2023
05611bd
mbedtls version fix
nminaylov Dec 12, 2023
102e891
Unused lib cleanup
nminaylov Dec 12, 2023
98ec2ad
Making PVS happy & TODOs cleanup
nminaylov Dec 12, 2023
4531909
TODOs cleanup #2
nminaylov Dec 12, 2023
471df94
Merge remote-tracking branch 'origin/dev' into nm/js_runner
skotopes Dec 19, 2023
d916ff4
Merge branch 'dev' into nm/js_runner
skotopes Dec 19, 2023
647decc
MJS: initial typed arrays support
nminaylov Dec 28, 2023
211e914
Merge remote-tracking branch 'origin/dev' into nm/js_runner
skotopes Feb 12, 2024
0e8a785
JS: fix mem leak in uart destructor
skotopes Feb 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pvsoptions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/*
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e lib/mjs -e */arm-none-eabi/*
1 change: 1 addition & 0 deletions applications/main/archive/helpers/archive_browser.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ static const char* known_ext[] = {
[ArchiveFileTypeBadUsb] = ".txt",
[ArchiveFileTypeU2f] = "?",
[ArchiveFileTypeApplication] = ".fap",
[ArchiveFileTypeJS] = ".js",
[ArchiveFileTypeUpdateManifest] = ".fuf",
[ArchiveFileTypeFolder] = "?",
[ArchiveFileTypeUnknown] = "*",
Expand Down
1 change: 1 addition & 0 deletions applications/main/archive/helpers/archive_files.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ typedef enum {
ArchiveFileTypeU2f,
ArchiveFileTypeUpdateManifest,
ArchiveFileTypeApplication,
ArchiveFileTypeJS,
ArchiveFileTypeFolder,
ArchiveFileTypeUnknown,
ArchiveFileTypeLoading,
Expand Down
2 changes: 2 additions & 0 deletions applications/main/archive/scenes/archive_scene_browser.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ static const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) {
return "U2F";
case ArchiveFileTypeUpdateManifest:
return "UpdaterApp";
case ArchiveFileTypeJS:
return "JS Runner";
default:
return NULL;
}
Expand Down
1 change: 1 addition & 0 deletions applications/main/archive/views/archive_browser_view.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ static const Icon* ArchiveItemIcons[] = {
[ArchiveFileTypeUnknown] = &I_unknown_10px,
[ArchiveFileTypeLoading] = &I_loading_10px,
[ArchiveFileTypeApplication] = &I_unknown_10px,
[ArchiveFileTypeJS] = &I_js_script_10px,
};

void archive_browser_set_callback(
Expand Down
71 changes: 53 additions & 18 deletions applications/services/gui/modules/file_browser_worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ typedef enum {
(WorkerEvtStop | WorkerEvtLoad | WorkerEvtFolderEnter | WorkerEvtFolderExit | \
WorkerEvtFolderRefresh | WorkerEvtConfigChange)

ARRAY_DEF(idx_last_array, int32_t)
ARRAY_DEF(IdxLastArray, int32_t)
ARRAY_DEF(ExtFilterArray, FuriString*, FURI_STRING_OPLIST)

struct BrowserWorker {
FuriThread* thread;

FuriString* filter_extension;
FuriString* path_start;
FuriString* path_current;
FuriString* path_next;
Expand All @@ -46,7 +46,8 @@ struct BrowserWorker {
uint32_t load_count;
bool skip_assets;
bool hide_dot_files;
idx_last_array_t idx_last;
IdxLastArray_t idx_last;
ExtFilterArray_t ext_filter;

void* cb_ctx;
BrowserWorkerFolderOpenCallback folder_cb;
Expand Down Expand Up @@ -78,6 +79,31 @@ static bool browser_path_trim(FuriString* path) {
}
return is_root;
}
static void browser_parse_ext_filter(ExtFilterArray_t ext_filter, const char* filter_str) {
if(!filter_str) {
return;
}

size_t len = strlen(filter_str);
if(len == 0) {
return;
}

size_t str_offset = 0;
FuriString* ext_temp = furi_string_alloc();
while(1) {
size_t ext_len = strcspn(&filter_str[str_offset], "|");

furi_string_set_strn(ext_temp, &filter_str[str_offset], ext_len);
ExtFilterArray_push_back(ext_filter, ext_temp);

str_offset += ext_len + 1;
if(str_offset >= len) {
break;
}
}
furi_string_free(ext_temp);
}

static bool browser_filter_by_name(BrowserWorker* browser, FuriString* name, bool is_folder) {
// Skip dot files if enabled
Expand All @@ -96,12 +122,20 @@ static bool browser_filter_by_name(BrowserWorker* browser, FuriString* name, boo
}
} else {
// Filter files by extension
if((furi_string_empty(browser->filter_extension)) ||
(furi_string_cmp_str(browser->filter_extension, "*") == 0)) {
if(ExtFilterArray_size(browser->ext_filter) == 0) {
return true;
}
if(furi_string_end_with(name, browser->filter_extension)) {
return true;

ExtFilterArray_it_t it;
for(ExtFilterArray_it(it, browser->ext_filter); !ExtFilterArray_end_p(it);
ExtFilterArray_next(it)) {
FuriString* ext = *ExtFilterArray_cref(it);
if((furi_string_empty(ext)) || (furi_string_cmp_str(ext, "*") == 0)) {
return true;
}
if(furi_string_end_with(name, ext)) {
return true;
}
}
}
return false;
Expand Down Expand Up @@ -288,7 +322,7 @@ static int32_t browser_worker(void* context) {
if(browser_path_is_file(browser->path_next)) {
path_extract_filename(browser->path_next, filename, false);
}
idx_last_array_reset(browser->idx_last);
IdxLastArray_reset(browser->idx_last);

furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtFolderEnter);
}
Expand All @@ -298,7 +332,7 @@ static int32_t browser_worker(void* context) {
bool is_root = browser_folder_check_and_switch(path);

// Push previous selected item index to history array
idx_last_array_push_back(browser->idx_last, browser->item_sel_idx);
IdxLastArray_push_back(browser->idx_last, browser->item_sel_idx);

int32_t file_idx = 0;
browser_folder_init(browser, path, filename, &items_cnt, &file_idx);
Expand All @@ -321,9 +355,9 @@ static int32_t browser_worker(void* context) {

int32_t file_idx = 0;
browser_folder_init(browser, path, filename, &items_cnt, &file_idx);
if(idx_last_array_size(browser->idx_last) > 0) {
if(IdxLastArray_size(browser->idx_last) > 0) {
// Pop previous selected item index from history array
idx_last_array_pop_back(&file_idx, browser->idx_last);
IdxLastArray_pop_back(&file_idx, browser->idx_last);
}
furi_string_set(browser->path_current, path);
FURI_LOG_D(
Expand Down Expand Up @@ -375,14 +409,15 @@ static int32_t browser_worker(void* context) {
BrowserWorker* file_browser_worker_alloc(
FuriString* path,
const char* base_path,
const char* filter_ext,
const char* ext_filter,
bool skip_assets,
bool hide_dot_files) {
BrowserWorker* browser = malloc(sizeof(BrowserWorker));

idx_last_array_init(browser->idx_last);
IdxLastArray_init(browser->idx_last);
ExtFilterArray_init(browser->ext_filter);

browser->filter_extension = furi_string_alloc_set(filter_ext);
browser_parse_ext_filter(browser->ext_filter, ext_filter);
browser->skip_assets = skip_assets;
browser->hide_dot_files = hide_dot_files;

Expand All @@ -407,12 +442,12 @@ void file_browser_worker_free(BrowserWorker* browser) {
furi_thread_join(browser->thread);
furi_thread_free(browser->thread);

furi_string_free(browser->filter_extension);
furi_string_free(browser->path_next);
furi_string_free(browser->path_current);
furi_string_free(browser->path_start);

idx_last_array_clear(browser->idx_last);
IdxLastArray_clear(browser->idx_last);
ExtFilterArray_clear(browser->ext_filter);

free(browser);
}
Expand Down Expand Up @@ -453,12 +488,12 @@ void file_browser_worker_set_long_load_callback(
void file_browser_worker_set_config(
BrowserWorker* browser,
FuriString* path,
const char* filter_ext,
const char* ext_filter,
bool skip_assets,
bool hide_dot_files) {
furi_assert(browser);
furi_string_set(browser->path_next, path);
furi_string_set(browser->filter_extension, filter_ext);
browser_parse_ext_filter(browser->ext_filter, ext_filter);
browser->skip_assets = skip_assets;
browser->hide_dot_files = hide_dot_files;
furi_thread_flags_set(furi_thread_get_id(browser->thread), WorkerEvtConfigChange);
Expand Down
4 changes: 2 additions & 2 deletions applications/services/gui/modules/file_browser_worker.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ typedef void (*BrowserWorkerLongLoadCallback)(void* context);
BrowserWorker* file_browser_worker_alloc(
FuriString* path,
const char* base_path,
const char* filter_ext,
const char* ext_filter,
bool skip_assets,
bool hide_dot_files);

Expand All @@ -51,7 +51,7 @@ void file_browser_worker_set_long_load_callback(
void file_browser_worker_set_config(
BrowserWorker* browser,
FuriString* path,
const char* filter_ext,
const char* ext_filter,
bool skip_assets,
bool hide_dot_files);

Expand Down
39 changes: 26 additions & 13 deletions applications/services/loader/loader_applications.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
#include <gui/view_holder.h>
#include <gui/modules/loading.h>
#include <dolphin/dolphin.h>
#include <lib/toolbox/path.h>

#define TAG "LoaderApplications"

#define JS_RUNNER_APP "JS Runner"

struct LoaderApplications {
FuriThread* thread;
void (*closed_cb)(void*);
Expand All @@ -36,7 +39,7 @@ void loader_applications_free(LoaderApplications* loader_applications) {
}

typedef struct {
FuriString* fap_path;
FuriString* file_path;
DialogsApp* dialogs;
Storage* storage;
Loader* loader;
Expand All @@ -48,7 +51,7 @@ typedef struct {

static LoaderApplicationsApp* loader_applications_app_alloc() {
LoaderApplicationsApp* app = malloc(sizeof(LoaderApplicationsApp)); //-V799
app->fap_path = furi_string_alloc_set(EXT_PATH("apps"));
app->file_path = furi_string_alloc_set(EXT_PATH("apps"));
app->dialogs = furi_record_open(RECORD_DIALOGS);
app->storage = furi_record_open(RECORD_STORAGE);
app->loader = furi_record_open(RECORD_LOADER);
Expand All @@ -73,7 +76,7 @@ static void loader_applications_app_free(LoaderApplicationsApp* app) {
furi_record_close(RECORD_LOADER);
furi_record_close(RECORD_DIALOGS);
furi_record_close(RECORD_STORAGE);
furi_string_free(app->fap_path);
furi_string_free(app->file_path);
free(app);
}

Expand All @@ -84,13 +87,19 @@ static bool loader_applications_item_callback(
FuriString* item_name) {
LoaderApplicationsApp* loader_applications_app = context;
furi_assert(loader_applications_app);
return flipper_application_load_name_and_icon(
path, loader_applications_app->storage, icon_ptr, item_name);
if(furi_string_end_with(path, ".fap")) {
return flipper_application_load_name_and_icon(
path, loader_applications_app->storage, icon_ptr, item_name);
} else {
path_extract_filename(path, item_name, false);
memcpy(*icon_ptr, icon_get_data(&I_js_script_10px), FAP_MANIFEST_MAX_ICON_SIZE);
return true;
}
}

static bool loader_applications_select_app(LoaderApplicationsApp* loader_applications_app) {
const DialogsFileBrowserOptions browser_options = {
.extension = ".fap",
.extension = ".fap|.js",
.skip_assets = true,
.icon = &I_unknown_10px,
.hide_ext = true,
Expand All @@ -101,8 +110,8 @@ static bool loader_applications_select_app(LoaderApplicationsApp* loader_applica

return dialog_file_browser_show(
loader_applications_app->dialogs,
loader_applications_app->fap_path,
loader_applications_app->fap_path,
loader_applications_app->file_path,
loader_applications_app->file_path,
&browser_options);
}

Expand All @@ -117,17 +126,16 @@ static void loader_pubsub_callback(const void* message, void* context) {
}
}

static void loader_applications_start_app(LoaderApplicationsApp* app) {
const char* name = furi_string_get_cstr(app->fap_path);

static void
loader_applications_start_app(LoaderApplicationsApp* app, const char* name, const char* args) {
dolphin_deed(DolphinDeedPluginStart);

// load app
FuriThreadId thread_id = furi_thread_get_current_id();
FuriPubSubSubscription* subscription =
furi_pubsub_subscribe(loader_get_pubsub(app->loader), loader_pubsub_callback, thread_id);

LoaderStatus status = loader_start_with_gui_error(app->loader, name, NULL);
LoaderStatus status = loader_start_with_gui_error(app->loader, name, args);

if(status == LoaderStatusOk) {
furi_thread_flags_wait(APPLICATION_STOP_EVENT, FuriFlagWaitAny, FuriWaitForever);
Expand All @@ -144,7 +152,12 @@ static int32_t loader_applications_thread(void* p) {
view_holder_start(app->view_holder);

while(loader_applications_select_app(app)) {
loader_applications_start_app(app);
if(!furi_string_end_with(app->file_path, ".js")) {
loader_applications_start_app(app, furi_string_get_cstr(app->file_path), NULL);
} else {
loader_applications_start_app(
app, JS_RUNNER_APP, furi_string_get_cstr(app->file_path));
}
}

// stop loading animation
Expand Down
1 change: 1 addition & 0 deletions applications/system/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ App(
provides=[
"updater_app",
"storage_move_to_sd",
"js_app",
# "archive",
],
)
41 changes: 41 additions & 0 deletions applications/system/js_app/application.fam
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
App(
appid="js_app",
name="JS Runner",
apptype=FlipperAppType.SYSTEM,
entry_point="js_app",
stack_size=2 * 1024,
resources="examples",
order=0,
)

App(
appid="js_dialog",
apptype=FlipperAppType.PLUGIN,
entry_point="js_dialog_ep",
requires=["js_app"],
sources=["modules/js_dialog.c"],
)

App(
appid="js_notification",
apptype=FlipperAppType.PLUGIN,
entry_point="js_notification_ep",
requires=["js_app"],
sources=["modules/js_notification.c"],
)

App(
appid="js_badusb",
apptype=FlipperAppType.PLUGIN,
entry_point="js_badusb_ep",
requires=["js_app"],
sources=["modules/js_badusb.c"],
)

App(
appid="js_uart",
apptype=FlipperAppType.PLUGIN,
entry_point="js_uart_ep",
requires=["js_app"],
sources=["modules/js_uart.c"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
let arr_1 = Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
print("len =", arr_1.buffer.byteLength);

let arr_2 = Uint8Array(arr_1.buffer.slice(2, 6));
print("slice len =", arr_2.buffer.byteLength);
for (let i = 0; i < arr_2.buffer.byteLength; i++) {
print(arr_2[i]);
}
Loading