mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-13 13:09:49 +04:00
Various fixes
fixes by Willy-JL nfc parser by zacharyweiss js widget and path globals by jamisonderek
This commit is contained in:
@@ -128,6 +128,15 @@ App(
|
||||
sources=["plugins/supported_cards/metromoney.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="charliecard_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="charliecard_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/charliecard.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="kazan_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
|
||||
1059
applications/main/nfc/plugins/supported_cards/charliecard.c
Normal file
1059
applications/main/nfc/plugins/supported_cards/charliecard.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -33,8 +33,10 @@ static void desktop_loader_callback(const void* message, void* context) {
|
||||
const LoaderEvent* event = message;
|
||||
|
||||
if(event->type == LoaderEventTypeApplicationStarted) {
|
||||
desktop->animation_lock = api_lock_alloc_locked();
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalBeforeAppStarted);
|
||||
furi_check(furi_semaphore_acquire(desktop->animation_semaphore, 3000) == FuriStatusOk);
|
||||
api_lock_wait_unlock_and_free(desktop->animation_lock);
|
||||
desktop->animation_lock = NULL;
|
||||
} else if(event->type == LoaderEventTypeApplicationStopped) {
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAfterAppFinished);
|
||||
}
|
||||
@@ -126,7 +128,7 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) {
|
||||
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
||||
}
|
||||
desktop_auto_lock_inhibit(desktop);
|
||||
furi_semaphore_release(desktop->animation_semaphore);
|
||||
api_lock_unlock(desktop->animation_lock);
|
||||
return true;
|
||||
case DesktopGlobalAfterAppFinished:
|
||||
animation_manager_load_and_continue_animation(desktop->animation_manager);
|
||||
@@ -276,7 +278,6 @@ void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled) {
|
||||
Desktop* desktop_alloc(void) {
|
||||
Desktop* desktop = malloc(sizeof(Desktop));
|
||||
|
||||
desktop->animation_semaphore = furi_semaphore_alloc(1, 0);
|
||||
desktop->animation_manager = animation_manager_alloc();
|
||||
desktop->gui = furi_record_open(RECORD_GUI);
|
||||
desktop->scene_thread = furi_thread_alloc();
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <loader/loader.h>
|
||||
#include <notification/notification_app.h>
|
||||
#include <toolbox/api_lock.h>
|
||||
|
||||
#define STATUS_BAR_Y_SHIFT 13
|
||||
|
||||
@@ -81,7 +82,7 @@ struct Desktop {
|
||||
|
||||
bool in_transition : 1;
|
||||
|
||||
FuriSemaphore* animation_semaphore;
|
||||
FuriApiLock animation_lock;
|
||||
};
|
||||
|
||||
Desktop* desktop_alloc(void);
|
||||
|
||||
@@ -109,3 +109,11 @@ App(
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_textbox.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_widget",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_widget_ep",
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_widget.c"],
|
||||
)
|
||||
|
||||
9
applications/system/js_app/examples/apps/Scripts/path.js
Normal file
9
applications/system/js_app/examples/apps/Scripts/path.js
Normal file
@@ -0,0 +1,9 @@
|
||||
let storage = require("storage");
|
||||
|
||||
print("script has __dirpath of" + __dirpath);
|
||||
print("script has __filepath of" + __filepath);
|
||||
if (storage.exists(__dirpath + "/math.js")) {
|
||||
print("math.js exist here.");
|
||||
} else {
|
||||
print("math.js does not exist here.");
|
||||
}
|
||||
BIN
applications/system/js_app/examples/apps/Scripts/widget-js.fxbm
Normal file
BIN
applications/system/js_app/examples/apps/Scripts/widget-js.fxbm
Normal file
Binary file not shown.
59
applications/system/js_app/examples/apps/Scripts/widget.js
Normal file
59
applications/system/js_app/examples/apps/Scripts/widget.js
Normal file
@@ -0,0 +1,59 @@
|
||||
let widget = require("widget");
|
||||
|
||||
let demo_seconds = 30;
|
||||
|
||||
print("Loading file", __filepath);
|
||||
print("From directory", __dirpath);
|
||||
|
||||
// addText supports "Primary" and "Secondary" font sizes.
|
||||
widget.addText(10, 10, "Primary", "Example JS widget");
|
||||
widget.addText(10, 20, "Secondary", "Example widget from JS!");
|
||||
|
||||
// load a Xbm file from the same directory as this script.
|
||||
widget.addText(0, 30, "Secondary", __filepath);
|
||||
let logo = widget.loadImageXbm(__dirpath + "/widget-js.fxbm");
|
||||
|
||||
// add a line (x1, y1, x2, y2)
|
||||
widget.addLine(10, 35, 120, 35);
|
||||
|
||||
// add a circle/disc (x, y, radius)
|
||||
widget.addCircle(12, 52, 10);
|
||||
widget.addDisc(12, 52, 5);
|
||||
|
||||
// add a frame/box (x, y, width, height)
|
||||
widget.addFrame(30, 45, 10, 10);
|
||||
widget.addBox(32, 47, 6, 6);
|
||||
|
||||
// add a rounded frame/box (x, y, width, height, radius)
|
||||
widget.addRframe(50, 45, 15, 15, 3);
|
||||
widget.addRbox(53, 48, 6, 6, 2);
|
||||
|
||||
// add a dot (x, y)
|
||||
widget.addDot(100, 45);
|
||||
widget.addDot(102, 44);
|
||||
widget.addDot(104, 43);
|
||||
|
||||
// add a glyph (x, y, glyph)
|
||||
widget.addGlyph(115, 50, "#".charCodeAt(0));
|
||||
|
||||
// Show the widget (drawing the layers in the orderer they were added)
|
||||
widget.show();
|
||||
|
||||
let i = 1;
|
||||
let bitmap = undefined;
|
||||
while (widget.isOpen() && i <= demo_seconds) {
|
||||
// Print statements will only show up once the widget is closed.
|
||||
print("count is at", i++);
|
||||
|
||||
// You can call remove on any added item, it does not impact the other ids.
|
||||
if (bitmap) { widget.remove(bitmap); bitmap = undefined; }
|
||||
// All of the addXXX functions return an id that can be used to remove the item.
|
||||
else { bitmap = widget.addXbm(77, 45, logo); }
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
// If user did not press the back button, close the widget.
|
||||
if (widget.isOpen()) {
|
||||
widget.close();
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <common/cs_dbg.h>
|
||||
#include <toolbox/path.h>
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
#include <loader/firmware_api/firmware_api.h>
|
||||
#include <flipper_application/api_hashtable/api_hashtable.h>
|
||||
@@ -319,6 +320,24 @@ static int32_t js_thread(void* arg) {
|
||||
struct mjs* mjs = mjs_create(worker);
|
||||
worker->modules = js_modules_create(mjs, worker->resolver);
|
||||
mjs_val_t global = mjs_get_global(mjs);
|
||||
if(worker->path) {
|
||||
FuriString* dirpath = furi_string_alloc();
|
||||
path_extract_dirname(furi_string_get_cstr(worker->path), dirpath);
|
||||
mjs_set(
|
||||
mjs,
|
||||
global,
|
||||
"__filepath",
|
||||
~0,
|
||||
mjs_mk_string(
|
||||
mjs, furi_string_get_cstr(worker->path), furi_string_size(worker->path), true));
|
||||
mjs_set(
|
||||
mjs,
|
||||
global,
|
||||
"__dirpath",
|
||||
~0,
|
||||
mjs_mk_string(mjs, furi_string_get_cstr(dirpath), furi_string_size(dirpath), true));
|
||||
furi_string_free(dirpath);
|
||||
}
|
||||
mjs_set(mjs, global, "print", ~0, MJS_MK_FN(js_print));
|
||||
mjs_set(mjs, global, "delay", ~0, MJS_MK_FN(js_delay));
|
||||
mjs_set(mjs, global, "to_string", ~0, MJS_MK_FN(js_global_to_string));
|
||||
|
||||
@@ -211,7 +211,7 @@ void js_math_random(struct mjs* mjs) {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
const uint32_t random_val = furi_hal_random_get();
|
||||
double rnd = (double)random_val / RAND_MAX;
|
||||
double rnd = (double)random_val / FURI_HAL_RANDOM_MAX;
|
||||
mjs_return(mjs, mjs_mk_number(mjs, rnd));
|
||||
}
|
||||
|
||||
|
||||
956
applications/system/js_app/modules/js_widget.c
Normal file
956
applications/system/js_app/modules/js_widget.c
Normal file
@@ -0,0 +1,956 @@
|
||||
#include <assets_icons.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/view.h>
|
||||
#include <m-array.h>
|
||||
#include <m-list.h>
|
||||
#include <string.h>
|
||||
#include "../js_modules.h"
|
||||
|
||||
typedef struct WidgetComponent WidgetComponent;
|
||||
ARRAY_DEF(ComponentArray, WidgetComponent*, M_PTR_OPLIST);
|
||||
|
||||
typedef struct XbmImage XbmImage;
|
||||
LIST_DEF(XbmImageList, XbmImage*, M_POD_OPLIST);
|
||||
|
||||
struct WidgetComponent {
|
||||
void (*draw)(Canvas* canvas, void* model);
|
||||
void (*free)(WidgetComponent* component);
|
||||
void* model;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
struct XbmImage {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint8_t data[];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t w;
|
||||
uint8_t h;
|
||||
} BoxElement;
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t r;
|
||||
} CircleElement;
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t r;
|
||||
} DiscElement;
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
} DotElement;
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
const Icon* icon;
|
||||
} IconElement;
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t w;
|
||||
uint8_t h;
|
||||
} FrameElement;
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint16_t ch;
|
||||
} GlyphElement;
|
||||
|
||||
typedef struct {
|
||||
uint8_t x1;
|
||||
uint8_t y1;
|
||||
uint8_t x2;
|
||||
uint8_t y2;
|
||||
} LineElement;
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t w;
|
||||
uint8_t h;
|
||||
uint8_t r;
|
||||
} RboxElement;
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t w;
|
||||
uint8_t h;
|
||||
uint8_t r;
|
||||
} RframeElement;
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
Font font;
|
||||
FuriString* text;
|
||||
} TextElement;
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint32_t index;
|
||||
View* view;
|
||||
} XbmElement;
|
||||
|
||||
typedef struct {
|
||||
ComponentArray_t component;
|
||||
XbmImageList_t image;
|
||||
uint32_t max_assigned_id;
|
||||
} WidgetModel;
|
||||
|
||||
typedef struct {
|
||||
View* view;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
FuriThread* thread;
|
||||
} JsWidgetInst;
|
||||
|
||||
static JsWidgetInst* get_this_ctx(struct mjs* mjs) {
|
||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||
JsWidgetInst* widget = mjs_get_ptr(mjs, obj_inst);
|
||||
furi_assert(widget);
|
||||
return widget;
|
||||
}
|
||||
|
||||
static void ret_bad_args(struct mjs* mjs, const char* error) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "%s", error);
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
||||
static bool check_arg_count(struct mjs* mjs, size_t count) {
|
||||
size_t num_args = mjs_nargs(mjs);
|
||||
if(num_args != count) {
|
||||
ret_bad_args(mjs, "Wrong argument count");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void js_widget_load_image_xbm(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mjs_val_t path_arg = mjs_arg(mjs, 0);
|
||||
size_t path_len = 0;
|
||||
const char* path = mjs_get_string(mjs, &path_arg, &path_len);
|
||||
if(!path) {
|
||||
ret_bad_args(mjs, "Path must be a string");
|
||||
return;
|
||||
}
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(storage);
|
||||
XbmImage* xbm = NULL;
|
||||
|
||||
do {
|
||||
if(!storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
ret_bad_args(mjs, "Failed to open file");
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t size = 0;
|
||||
if(storage_file_read(file, &size, sizeof(size)) != sizeof(size)) {
|
||||
ret_bad_args(mjs, "Failed to get file size");
|
||||
break;
|
||||
}
|
||||
|
||||
xbm = malloc(size);
|
||||
if(storage_file_read(file, xbm, size) != size) {
|
||||
ret_bad_args(mjs, "Failed to load entire file");
|
||||
free(xbm);
|
||||
xbm = NULL;
|
||||
break;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
storage_file_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
if(xbm == NULL) {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t count = 0;
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
count = XbmImageList_size(model->image);
|
||||
XbmImageList_push_back(model->image, xbm);
|
||||
},
|
||||
false);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, count));
|
||||
}
|
||||
|
||||
static void js_widget_remove(struct mjs* mjs) {
|
||||
bool removed = false;
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
uint32_t id = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||
ComponentArray_it_t it;
|
||||
ComponentArray_it(it, model->component);
|
||||
while(!ComponentArray_end_p(it)) {
|
||||
WidgetComponent* component = *ComponentArray_ref(it);
|
||||
if(component->id == id) {
|
||||
if(component->free) {
|
||||
component->free(component);
|
||||
}
|
||||
ComponentArray_remove(model->component, it);
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
ComponentArray_next(it);
|
||||
}
|
||||
},
|
||||
true);
|
||||
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, removed));
|
||||
}
|
||||
|
||||
static void widget_box_draw(Canvas* canvas, void* model) {
|
||||
BoxElement* element = model;
|
||||
canvas_draw_box(canvas, element->x, element->y, element->w, element->h);
|
||||
}
|
||||
|
||||
static void widget_box_free(WidgetComponent* component) {
|
||||
BoxElement* element = component->model;
|
||||
free(element);
|
||||
free(component);
|
||||
}
|
||||
|
||||
static void js_widget_add_box(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 4)) return;
|
||||
|
||||
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||
int32_t w = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||
int32_t h = mjs_get_int32(mjs, mjs_arg(mjs, 3));
|
||||
|
||||
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||
component->draw = widget_box_draw;
|
||||
component->free = widget_box_free;
|
||||
component->model = malloc(sizeof(BoxElement));
|
||||
BoxElement* element = component->model;
|
||||
element->x = x;
|
||||
element->y = y;
|
||||
element->w = w;
|
||||
element->h = h;
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
++model->max_assigned_id;
|
||||
component->id = model->max_assigned_id;
|
||||
ComponentArray_push_back(model->component, component);
|
||||
},
|
||||
true);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||
}
|
||||
|
||||
static void widget_circle_draw(Canvas* canvas, void* model) {
|
||||
CircleElement* element = model;
|
||||
canvas_draw_circle(canvas, element->x, element->y, element->r);
|
||||
}
|
||||
|
||||
static void widget_circle_free(WidgetComponent* component) {
|
||||
CircleElement* element = component->model;
|
||||
free(element);
|
||||
free(component);
|
||||
}
|
||||
|
||||
static void js_widget_add_circle(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 3)) return;
|
||||
|
||||
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||
int32_t r = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||
|
||||
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||
component->draw = widget_circle_draw;
|
||||
component->free = widget_circle_free;
|
||||
component->model = malloc(sizeof(CircleElement));
|
||||
CircleElement* element = component->model;
|
||||
element->x = x;
|
||||
element->y = y;
|
||||
element->r = r;
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
++model->max_assigned_id;
|
||||
component->id = model->max_assigned_id;
|
||||
ComponentArray_push_back(model->component, component);
|
||||
},
|
||||
true);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||
}
|
||||
|
||||
static void widget_disc_draw(Canvas* canvas, void* model) {
|
||||
DiscElement* element = model;
|
||||
canvas_draw_disc(canvas, element->x, element->y, element->r);
|
||||
}
|
||||
|
||||
static void widget_disc_free(WidgetComponent* component) {
|
||||
DiscElement* element = component->model;
|
||||
free(element);
|
||||
free(component);
|
||||
}
|
||||
|
||||
static void js_widget_add_disc(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 3)) return;
|
||||
|
||||
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||
int32_t r = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||
|
||||
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||
component->draw = widget_disc_draw;
|
||||
component->free = widget_disc_free;
|
||||
component->model = malloc(sizeof(DiscElement));
|
||||
DiscElement* element = component->model;
|
||||
element->x = x;
|
||||
element->y = y;
|
||||
element->r = r;
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
++model->max_assigned_id;
|
||||
component->id = model->max_assigned_id;
|
||||
ComponentArray_push_back(model->component, component);
|
||||
},
|
||||
true);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||
}
|
||||
|
||||
static void widget_dot_draw(Canvas* canvas, void* model) {
|
||||
DotElement* element = model;
|
||||
canvas_draw_dot(canvas, element->x, element->y);
|
||||
}
|
||||
|
||||
static void widget_dot_free(WidgetComponent* component) {
|
||||
DotElement* element = component->model;
|
||||
free(element);
|
||||
free(component);
|
||||
}
|
||||
|
||||
static void js_widget_add_dot(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 2)) return;
|
||||
|
||||
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||
|
||||
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||
component->draw = widget_dot_draw;
|
||||
component->free = widget_dot_free;
|
||||
component->model = malloc(sizeof(DotElement));
|
||||
DotElement* element = component->model;
|
||||
element->x = x;
|
||||
element->y = y;
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
++model->max_assigned_id;
|
||||
component->id = model->max_assigned_id;
|
||||
ComponentArray_push_back(model->component, component);
|
||||
},
|
||||
true);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||
}
|
||||
|
||||
static void widget_frame_draw(Canvas* canvas, void* model) {
|
||||
FrameElement* element = model;
|
||||
canvas_draw_frame(canvas, element->x, element->y, element->w, element->h);
|
||||
}
|
||||
|
||||
static void widget_frame_free(WidgetComponent* component) {
|
||||
FrameElement* element = component->model;
|
||||
free(element);
|
||||
free(component);
|
||||
}
|
||||
|
||||
static void js_widget_add_frame(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 4)) return;
|
||||
|
||||
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||
int32_t w = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||
int32_t h = mjs_get_int32(mjs, mjs_arg(mjs, 3));
|
||||
|
||||
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||
component->draw = widget_frame_draw;
|
||||
component->free = widget_frame_free;
|
||||
component->model = malloc(sizeof(FrameElement));
|
||||
FrameElement* element = component->model;
|
||||
element->x = x;
|
||||
element->y = y;
|
||||
element->w = w;
|
||||
element->h = h;
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
++model->max_assigned_id;
|
||||
component->id = model->max_assigned_id;
|
||||
ComponentArray_push_back(model->component, component);
|
||||
},
|
||||
true);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||
}
|
||||
|
||||
static void widget_glyph_draw(Canvas* canvas, void* model) {
|
||||
GlyphElement* element = model;
|
||||
canvas_draw_glyph(canvas, element->x, element->y, element->ch);
|
||||
}
|
||||
|
||||
static void widget_glyph_free(WidgetComponent* component) {
|
||||
GlyphElement* element = component->model;
|
||||
free(element);
|
||||
free(component);
|
||||
}
|
||||
|
||||
static void js_widget_add_glyph(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 3)) return;
|
||||
|
||||
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||
int32_t ch = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||
|
||||
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||
component->draw = widget_glyph_draw;
|
||||
component->free = widget_glyph_free;
|
||||
component->model = malloc(sizeof(GlyphElement));
|
||||
GlyphElement* element = component->model;
|
||||
element->x = x;
|
||||
element->y = y;
|
||||
element->ch = ch;
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
++model->max_assigned_id;
|
||||
component->id = model->max_assigned_id;
|
||||
ComponentArray_push_back(model->component, component);
|
||||
},
|
||||
true);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||
}
|
||||
|
||||
static void widget_line_draw(Canvas* canvas, void* model) {
|
||||
LineElement* element = model;
|
||||
canvas_draw_line(canvas, element->x1, element->y1, element->x2, element->y2);
|
||||
}
|
||||
|
||||
static void widget_line_free(WidgetComponent* component) {
|
||||
LineElement* element = component->model;
|
||||
free(element);
|
||||
free(component);
|
||||
}
|
||||
|
||||
static void js_widget_add_line(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 4)) return;
|
||||
|
||||
int32_t x1 = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||
int32_t y1 = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||
int32_t x2 = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||
int32_t y2 = mjs_get_int32(mjs, mjs_arg(mjs, 3));
|
||||
|
||||
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||
component->draw = widget_line_draw;
|
||||
component->free = widget_line_free;
|
||||
component->model = malloc(sizeof(LineElement));
|
||||
LineElement* element = component->model;
|
||||
element->x1 = x1;
|
||||
element->y1 = y1;
|
||||
element->x2 = x2;
|
||||
element->y2 = y2;
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
++model->max_assigned_id;
|
||||
component->id = model->max_assigned_id;
|
||||
ComponentArray_push_back(model->component, component);
|
||||
},
|
||||
true);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||
}
|
||||
|
||||
static void widget_rbox_draw(Canvas* canvas, void* model) {
|
||||
RboxElement* element = model;
|
||||
canvas_draw_rbox(canvas, element->x, element->y, element->w, element->h, element->r);
|
||||
}
|
||||
|
||||
static void widget_rbox_free(WidgetComponent* component) {
|
||||
BoxElement* element = component->model;
|
||||
free(element);
|
||||
free(component);
|
||||
}
|
||||
|
||||
static void js_widget_add_rbox(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 5)) return;
|
||||
|
||||
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||
int32_t w = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||
int32_t h = mjs_get_int32(mjs, mjs_arg(mjs, 3));
|
||||
int32_t r = mjs_get_int32(mjs, mjs_arg(mjs, 4));
|
||||
|
||||
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||
component->draw = widget_rbox_draw;
|
||||
component->free = widget_rbox_free;
|
||||
component->model = malloc(sizeof(RboxElement));
|
||||
RboxElement* element = component->model;
|
||||
element->x = x;
|
||||
element->y = y;
|
||||
element->w = w;
|
||||
element->h = h;
|
||||
element->r = r;
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
++model->max_assigned_id;
|
||||
component->id = model->max_assigned_id;
|
||||
ComponentArray_push_back(model->component, component);
|
||||
},
|
||||
true);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||
}
|
||||
|
||||
static void widget_rframe_draw(Canvas* canvas, void* model) {
|
||||
RframeElement* element = model;
|
||||
canvas_draw_rframe(canvas, element->x, element->y, element->w, element->h, element->r);
|
||||
}
|
||||
|
||||
static void widget_rframe_free(WidgetComponent* component) {
|
||||
RframeElement* element = component->model;
|
||||
free(element);
|
||||
free(component);
|
||||
}
|
||||
|
||||
static void js_widget_add_rframe(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 5)) return;
|
||||
|
||||
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||
int32_t w = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||
int32_t h = mjs_get_int32(mjs, mjs_arg(mjs, 3));
|
||||
int32_t r = mjs_get_int32(mjs, mjs_arg(mjs, 4));
|
||||
|
||||
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||
component->draw = widget_rframe_draw;
|
||||
component->free = widget_rframe_free;
|
||||
component->model = malloc(sizeof(RframeElement));
|
||||
RframeElement* element = component->model;
|
||||
element->x = x;
|
||||
element->y = y;
|
||||
element->w = w;
|
||||
element->h = h;
|
||||
element->r = r;
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
++model->max_assigned_id;
|
||||
component->id = model->max_assigned_id;
|
||||
ComponentArray_push_back(model->component, component);
|
||||
},
|
||||
true);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||
}
|
||||
|
||||
static void widget_text_draw(Canvas* canvas, void* model) {
|
||||
TextElement* element = model;
|
||||
canvas_set_font(canvas, element->font);
|
||||
canvas_draw_str(canvas, element->x, element->y, furi_string_get_cstr(element->text));
|
||||
}
|
||||
|
||||
static void widget_text_free(WidgetComponent* component) {
|
||||
TextElement* element = component->model;
|
||||
furi_string_free(element->text);
|
||||
free(element);
|
||||
free(component);
|
||||
}
|
||||
|
||||
static void js_widget_add_text(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 4)) return;
|
||||
|
||||
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||
|
||||
mjs_val_t font_arg = mjs_arg(mjs, 2);
|
||||
size_t font_name_len = 0;
|
||||
const char* font_name_text = mjs_get_string(mjs, &font_arg, &font_name_len);
|
||||
if(!font_name_text) {
|
||||
ret_bad_args(mjs, "Font name must be a string");
|
||||
return;
|
||||
}
|
||||
|
||||
Font font = FontTotalNumber;
|
||||
size_t cmp_str_len = strlen("Primary");
|
||||
if(font_name_len == cmp_str_len && strncmp(font_name_text, "Primary", cmp_str_len) == 0) {
|
||||
font = FontPrimary;
|
||||
} else {
|
||||
cmp_str_len = strlen("Secondary");
|
||||
if(font_name_len == cmp_str_len &&
|
||||
strncmp(font_name_text, "Secondary", cmp_str_len) == 0) {
|
||||
font = FontSecondary;
|
||||
}
|
||||
}
|
||||
if(font == FontTotalNumber) {
|
||||
ret_bad_args(mjs, "Unknown font name");
|
||||
return;
|
||||
}
|
||||
|
||||
mjs_val_t text_arg = mjs_arg(mjs, 3);
|
||||
size_t text_len = 0;
|
||||
const char* text = mjs_get_string(mjs, &text_arg, &text_len);
|
||||
if(!text) {
|
||||
ret_bad_args(mjs, "Text must be a string");
|
||||
return;
|
||||
}
|
||||
FuriString* text_str = furi_string_alloc_set(text);
|
||||
|
||||
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||
component->draw = widget_text_draw;
|
||||
component->free = widget_text_free;
|
||||
component->model = malloc(sizeof(TextElement));
|
||||
TextElement* element = component->model;
|
||||
element->x = x;
|
||||
element->y = y;
|
||||
element->font = font;
|
||||
element->text = text_str;
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
++model->max_assigned_id;
|
||||
component->id = model->max_assigned_id;
|
||||
ComponentArray_push_back(model->component, component);
|
||||
},
|
||||
true);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||
}
|
||||
|
||||
static void widget_xbm_draw(Canvas* canvas, void* model) {
|
||||
XbmElement* element = model;
|
||||
XbmImage* image = NULL;
|
||||
|
||||
with_view_model(
|
||||
element->view,
|
||||
WidgetModel * widget_model,
|
||||
{ image = *XbmImageList_get(widget_model->image, element->index); },
|
||||
false);
|
||||
|
||||
if(image) {
|
||||
canvas_draw_xbm(canvas, element->x, element->y, image->width, image->height, image->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void widget_xbm_free(WidgetComponent* component) {
|
||||
XbmElement* element = component->model;
|
||||
free(element);
|
||||
free(component);
|
||||
}
|
||||
|
||||
static void js_widget_add_xbm(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 3)) return;
|
||||
|
||||
int32_t x = mjs_get_int32(mjs, mjs_arg(mjs, 0));
|
||||
int32_t y = mjs_get_int32(mjs, mjs_arg(mjs, 1));
|
||||
int32_t index = mjs_get_int32(mjs, mjs_arg(mjs, 2));
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * widget_model,
|
||||
{
|
||||
size_t count = XbmImageList_size(widget_model->image);
|
||||
if(index < 0 || index >= (int32_t)count) {
|
||||
ret_bad_args(mjs, "Invalid image index");
|
||||
return;
|
||||
}
|
||||
},
|
||||
false);
|
||||
|
||||
WidgetComponent* component = malloc(sizeof(WidgetComponent));
|
||||
component->draw = widget_xbm_draw;
|
||||
component->free = widget_xbm_free;
|
||||
component->model = malloc(sizeof(XbmElement));
|
||||
XbmElement* element = component->model;
|
||||
element->x = x;
|
||||
element->y = y;
|
||||
element->index = index;
|
||||
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
++model->max_assigned_id;
|
||||
component->id = model->max_assigned_id;
|
||||
element->view = widget->view;
|
||||
ComponentArray_push_back(model->component, component);
|
||||
},
|
||||
true);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, component->id));
|
||||
}
|
||||
|
||||
static void js_widget_is_open(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 0)) return;
|
||||
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, !!widget->thread));
|
||||
}
|
||||
|
||||
static void widget_deinit(void* context) {
|
||||
JsWidgetInst* widget = context;
|
||||
if(widget->thread) {
|
||||
furi_thread_join(widget->thread);
|
||||
furi_thread_free(widget->thread);
|
||||
widget->thread = NULL;
|
||||
|
||||
furi_assert(widget->view_dispatcher);
|
||||
view_dispatcher_remove_view(widget->view_dispatcher, 0);
|
||||
view_dispatcher_free(widget->view_dispatcher);
|
||||
widget->view_dispatcher = NULL;
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
}
|
||||
}
|
||||
|
||||
static void widget_callback(void* context, uint32_t arg) {
|
||||
UNUSED(arg);
|
||||
widget_deinit(context);
|
||||
}
|
||||
|
||||
static bool widget_exit(void* context) {
|
||||
JsWidgetInst* widget = context;
|
||||
view_dispatcher_stop(widget->view_dispatcher);
|
||||
furi_timer_pending_callback(widget_callback, widget, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int32_t widget_thread(void* context) {
|
||||
ViewDispatcher* view_dispatcher = context;
|
||||
view_dispatcher_run(view_dispatcher);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void js_widget_show(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 0)) return;
|
||||
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
widget->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(widget->view_dispatcher);
|
||||
view_dispatcher_add_view(widget->view_dispatcher, 0, widget->view);
|
||||
view_dispatcher_set_event_callback_context(widget->view_dispatcher, widget);
|
||||
view_dispatcher_set_navigation_event_callback(widget->view_dispatcher, widget_exit);
|
||||
view_dispatcher_attach_to_gui(widget->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_switch_to_view(widget->view_dispatcher, 0);
|
||||
|
||||
widget->thread =
|
||||
furi_thread_alloc_ex("JsWidget", 1024, widget_thread, widget->view_dispatcher);
|
||||
furi_thread_start(widget->thread);
|
||||
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
||||
static void js_widget_close(struct mjs* mjs) {
|
||||
JsWidgetInst* widget = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 0)) return;
|
||||
|
||||
if(widget->thread) {
|
||||
view_dispatcher_stop(widget->view_dispatcher);
|
||||
widget_deinit(widget);
|
||||
}
|
||||
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
||||
static void widget_draw_callback(Canvas* canvas, void* model) {
|
||||
WidgetModel* widget_model = model;
|
||||
canvas_clear(canvas);
|
||||
|
||||
ComponentArray_it_t it;
|
||||
ComponentArray_it(it, widget_model->component);
|
||||
while(!ComponentArray_end_p(it)) {
|
||||
WidgetComponent* component = *ComponentArray_ref(it);
|
||||
if(component->draw != NULL) {
|
||||
component->draw(canvas, component->model);
|
||||
}
|
||||
ComponentArray_next(it);
|
||||
}
|
||||
}
|
||||
|
||||
static void widget_remove_view(void* context) {
|
||||
JsWidgetInst* widget = context;
|
||||
|
||||
if(widget->view) {
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
ComponentArray_it_t it;
|
||||
ComponentArray_it(it, model->component);
|
||||
while(!ComponentArray_end_p(it)) {
|
||||
WidgetComponent* component = *ComponentArray_ref(it);
|
||||
if(component->free) {
|
||||
component->free(component);
|
||||
component->free = NULL;
|
||||
}
|
||||
ComponentArray_next(it);
|
||||
}
|
||||
ComponentArray_reset(model->component);
|
||||
ComponentArray_clear(model->component);
|
||||
},
|
||||
false);
|
||||
with_view_model(
|
||||
widget->view, WidgetModel * model, { XbmImageList_clear(model->image); }, false);
|
||||
view_free(widget->view);
|
||||
widget->view = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static JsWidgetInst* widget_alloc(void) {
|
||||
JsWidgetInst* widget = malloc(sizeof(JsWidgetInst));
|
||||
widget->thread = NULL;
|
||||
widget->view_dispatcher = NULL;
|
||||
|
||||
widget->view = view_alloc();
|
||||
view_allocate_model(widget->view, ViewModelTypeLockFree, sizeof(WidgetModel));
|
||||
view_set_draw_callback(widget->view, widget_draw_callback);
|
||||
with_view_model(
|
||||
widget->view,
|
||||
WidgetModel * model,
|
||||
{
|
||||
ComponentArray_init(model->component);
|
||||
XbmImageList_init(model->image);
|
||||
model->max_assigned_id = 0;
|
||||
},
|
||||
true);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
static void* js_widget_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
JsWidgetInst* widget = widget_alloc();
|
||||
mjs_val_t widget_obj = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, widget_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, widget));
|
||||
// addBox(x: number, y: number, w: number, h: number): number (returns id of the added component)
|
||||
mjs_set(mjs, widget_obj, "addBox", ~0, MJS_MK_FN(js_widget_add_box));
|
||||
// addCircle(x: number, y: number, r: number): number (returns id of the added component)
|
||||
mjs_set(mjs, widget_obj, "addCircle", ~0, MJS_MK_FN(js_widget_add_circle));
|
||||
// addDisc(x: number, y: number, r: number): number (returns id of the added component)
|
||||
mjs_set(mjs, widget_obj, "addDisc", ~0, MJS_MK_FN(js_widget_add_disc));
|
||||
// addDot(x: number, y: number): number (returns id of the added component)
|
||||
mjs_set(mjs, widget_obj, "addDot", ~0, MJS_MK_FN(js_widget_add_dot));
|
||||
// addFrame(x: number, y: number, w: number, h: number): number (returns id of the added component)
|
||||
mjs_set(mjs, widget_obj, "addFrame", ~0, MJS_MK_FN(js_widget_add_frame));
|
||||
// addGlyph(x: number, y: number, ch: number): number (returns id of the added component)
|
||||
mjs_set(mjs, widget_obj, "addGlyph", ~0, MJS_MK_FN(js_widget_add_glyph));
|
||||
// addLine(x1: number, y1: number, x2: number, y2: number): number (returns id of the added component)
|
||||
mjs_set(mjs, widget_obj, "addLine", ~0, MJS_MK_FN(js_widget_add_line));
|
||||
// addRbox(x: number, y: number, w: number, h: number, r: number): number (returns id of the added component)
|
||||
mjs_set(mjs, widget_obj, "addRbox", ~0, MJS_MK_FN(js_widget_add_rbox));
|
||||
// addRframe(x: number, y: number, w: number, h: number, r: number): number (returns id of the added component)
|
||||
mjs_set(mjs, widget_obj, "addRframe", ~0, MJS_MK_FN(js_widget_add_rframe));
|
||||
// addText(x: number, y: number, font: string, text: string): number (returns id of the added component)
|
||||
mjs_set(mjs, widget_obj, "addText", ~0, MJS_MK_FN(js_widget_add_text));
|
||||
// addXbm(x: number, y: number, index: number): number (returns id of the added component)
|
||||
mjs_set(mjs, widget_obj, "addXbm", ~0, MJS_MK_FN(js_widget_add_xbm));
|
||||
// loadImageXbm(path: string): number (returns index of the loaded image)
|
||||
mjs_set(mjs, widget_obj, "loadImageXbm", ~0, MJS_MK_FN(js_widget_load_image_xbm));
|
||||
// remove(id: number): boolean (returns true if the component was removed)
|
||||
mjs_set(mjs, widget_obj, "remove", ~0, MJS_MK_FN(js_widget_remove));
|
||||
// isOpen(): boolean (returns true if the widget is open)
|
||||
mjs_set(mjs, widget_obj, "isOpen", ~0, MJS_MK_FN(js_widget_is_open));
|
||||
// show(): void (shows the widget)
|
||||
mjs_set(mjs, widget_obj, "show", ~0, MJS_MK_FN(js_widget_show));
|
||||
// close(): void (closes the widget)
|
||||
mjs_set(mjs, widget_obj, "close", ~0, MJS_MK_FN(js_widget_close));
|
||||
*object = widget_obj;
|
||||
return widget;
|
||||
}
|
||||
|
||||
static void js_widget_destroy(void* inst) {
|
||||
JsWidgetInst* widget = inst;
|
||||
if(widget->thread) {
|
||||
view_dispatcher_stop(widget->view_dispatcher);
|
||||
widget_deinit(widget);
|
||||
}
|
||||
widget_remove_view(widget);
|
||||
free(widget);
|
||||
}
|
||||
|
||||
static const JsModuleDescriptor js_widget_desc = {
|
||||
"widget",
|
||||
js_widget_create,
|
||||
js_widget_destroy,
|
||||
};
|
||||
|
||||
static const FlipperAppPluginDescriptor widget_plugin_descriptor = {
|
||||
.appid = PLUGIN_APP_ID,
|
||||
.ep_api_version = PLUGIN_API_VERSION,
|
||||
.entry_point = &js_widget_desc,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* js_widget_ep(void) {
|
||||
return &widget_plugin_descriptor;
|
||||
}
|
||||
@@ -612,7 +612,7 @@ void infrared_worker_set_raw_signal(
|
||||
furi_check(timings);
|
||||
furi_check(timings_cnt > 0);
|
||||
furi_check((frequency <= INFRARED_MAX_FREQUENCY) && (frequency >= INFRARED_MIN_FREQUENCY));
|
||||
furi_check((duty_cycle < 1.0f) && (duty_cycle > 0.0f));
|
||||
furi_check((duty_cycle <= 1.0f) && (duty_cycle > 0.0f));
|
||||
|
||||
size_t max_copy_num = COUNT_OF(instance->signal.raw.timings) - 1;
|
||||
furi_check(timings_cnt <= max_copy_num);
|
||||
|
||||
@@ -41,7 +41,11 @@
|
||||
> If for any reason this test is never passed, this means there is a failure in the system and there is no other
|
||||
> way to recover than applying a device reset.
|
||||
*/
|
||||
#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS (3000U) /* 3 seconds */
|
||||
// Was previously 3000U, 3 seconds
|
||||
// Changing furi_assert() to furi_check() brought timeout crashes
|
||||
// Internal storage is very slow, and "big" files will often cause a "timeout" with 3 seconds
|
||||
// 10 seconds seems fine, the file operations complete successfully, albeit slowly
|
||||
#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS (10000U) /* 10 seconds */
|
||||
|
||||
#define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__) & 0x7U) == (0x00UL))
|
||||
#define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define FURI_HAL_RANDOM_MAX 0xFFFFFFFF
|
||||
|
||||
/** Initialize random subsystem */
|
||||
void furi_hal_random_init(void);
|
||||
|
||||
/** Get random value
|
||||
* furi_hal_random_get() gives up to FURI_HAL_RANDOM_MAX
|
||||
* rand() and random() give up to RAND_MAX
|
||||
*
|
||||
* @return random value
|
||||
* @return 32 bit random value (up to FURI_HAL_RANDOM_MAX)
|
||||
*/
|
||||
uint32_t furi_hal_random_get(void);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user