mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 20:49:49 +04:00
[FL-3963] Move JS modules to new arg parser (#4139)
* js: value destructuring and tests * js: temporary fix to see size impact * js_val: reduce code size 1 * i may be stupid. * test: js_value args * Revert "js: temporary fix to see size impact" This reverts commit f51d726dbafc4300d3552020de1c3b8f9ecd3ac1. * pvs: silence warnings * style: formatting * pvs: silence warnings? * pvs: silence warnings?? * js_value: redesign declaration types for less code * js: temporary fix to see size impact * style: formatting * pvs: fix helpful warnings * js_value: reduce .rodata size * pvs: fix helpful warning * js_value: reduce code size 1 * fix build error * style: format * Revert "js: temporary fix to see size impact" This reverts commit d6a46f01794132e882e03fd273dec24386a4f8ba. * style: format * js: move to new arg parser * style: format --------- Co-authored-by: hedger <hedger@users.noreply.github.com>
This commit is contained in:
@@ -202,12 +202,15 @@ static JsSdkCompatStatus
|
||||
return JsSdkCompatStatusCompatible;
|
||||
}
|
||||
|
||||
#define JS_SDK_COMPAT_ARGS \
|
||||
int32_t major, minor; \
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_INT32(&major), JS_ARG_INT32(&minor));
|
||||
static const JsValueDeclaration js_sdk_version_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
};
|
||||
static const JsValueArguments js_sdk_version_args = JS_VALUE_ARGS(js_sdk_version_arg_list);
|
||||
|
||||
void js_sdk_compatibility_status(struct mjs* mjs) {
|
||||
JS_SDK_COMPAT_ARGS;
|
||||
int32_t major, minor;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_sdk_version_args, &major, &minor);
|
||||
JsSdkCompatStatus status = js_internal_sdk_compatibility_status(major, minor);
|
||||
switch(status) {
|
||||
case JsSdkCompatStatusCompatible:
|
||||
@@ -223,7 +226,8 @@ void js_sdk_compatibility_status(struct mjs* mjs) {
|
||||
}
|
||||
|
||||
void js_is_sdk_compatible(struct mjs* mjs) {
|
||||
JS_SDK_COMPAT_ARGS;
|
||||
int32_t major, minor;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_sdk_version_args, &major, &minor);
|
||||
JsSdkCompatStatus status = js_internal_sdk_compatibility_status(major, minor);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, status == JsSdkCompatStatusCompatible));
|
||||
}
|
||||
@@ -246,7 +250,8 @@ static bool js_internal_compat_ask_user(const char* message) {
|
||||
}
|
||||
|
||||
void js_check_sdk_compatibility(struct mjs* mjs) {
|
||||
JS_SDK_COMPAT_ARGS;
|
||||
int32_t major, minor;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_sdk_version_args, &major, &minor);
|
||||
JsSdkCompatStatus status = js_internal_sdk_compatibility_status(major, minor);
|
||||
if(status != JsSdkCompatStatusCompatible) {
|
||||
FURI_LOG_E(
|
||||
@@ -300,15 +305,20 @@ static bool js_internal_supports_all_of(struct mjs* mjs, mjs_val_t feature_arr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static const JsValueDeclaration js_sdk_features_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeAnyArray),
|
||||
};
|
||||
static const JsValueArguments js_sdk_features_args = JS_VALUE_ARGS(js_sdk_features_arg_list);
|
||||
|
||||
void js_does_sdk_support(struct mjs* mjs) {
|
||||
mjs_val_t features;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_ARR(&features));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_sdk_features_args, &features);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, js_internal_supports_all_of(mjs, features)));
|
||||
}
|
||||
|
||||
void js_check_sdk_features(struct mjs* mjs) {
|
||||
mjs_val_t features;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_ARR(&features));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_sdk_features_args, &features);
|
||||
if(!js_internal_supports_all_of(mjs, features)) {
|
||||
FURI_LOG_E(TAG, "Script requests unsupported features");
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
#include <flipper_application/plugins/plugin_manager.h>
|
||||
#include <flipper_application/plugins/composite_resolver.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PLUGIN_APP_ID "js"
|
||||
#define PLUGIN_API_VERSION 1
|
||||
|
||||
@@ -64,226 +68,6 @@ typedef enum {
|
||||
JsForeignMagic_JsEventLoopContract,
|
||||
} JsForeignMagic;
|
||||
|
||||
// Are you tired of your silly little JS+C glue code functions being 75%
|
||||
// argument validation code and 25% actual logic? Introducing: ASS (Argument
|
||||
// Schema for Scripts)! ASS is a set of macros that reduce the typical
|
||||
// boilerplate code of "check argument count, get arguments, validate arguments,
|
||||
// extract C values from arguments" down to just one line!
|
||||
|
||||
/**
|
||||
* When passed as the second argument to `JS_FETCH_ARGS_OR_RETURN`, signifies
|
||||
* that the function requires exactly as many arguments as were specified.
|
||||
*/
|
||||
#define JS_EXACTLY ==
|
||||
/**
|
||||
* When passed as the second argument to `JS_FETCH_ARGS_OR_RETURN`, signifies
|
||||
* that the function requires at least as many arguments as were specified.
|
||||
*/
|
||||
#define JS_AT_LEAST >=
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
size_t value;
|
||||
} JsEnumMapping;
|
||||
|
||||
#define JS_ENUM_MAP(var_name, ...) \
|
||||
static const JsEnumMapping var_name##_mapping[] = { \
|
||||
{NULL, sizeof(var_name)}, \
|
||||
__VA_ARGS__, \
|
||||
{NULL, 0}, \
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
size_t offset;
|
||||
} JsObjectMapping;
|
||||
|
||||
#define JS_OBJ_MAP(var_name, ...) \
|
||||
static const JsObjectMapping var_name##_mapping[] = { \
|
||||
__VA_ARGS__, \
|
||||
{NULL, 0}, \
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
void* out;
|
||||
int (*validator)(mjs_val_t);
|
||||
void (*converter)(struct mjs*, mjs_val_t*, void* out, const void* extra);
|
||||
const char* expected_type;
|
||||
bool (*extended_validator)(struct mjs*, mjs_val_t, const void* extra);
|
||||
const void* extra_data;
|
||||
} _js_arg_decl;
|
||||
|
||||
static inline void _js_to_int32(struct mjs* mjs, mjs_val_t* in, void* out, const void* extra) {
|
||||
UNUSED(extra);
|
||||
*(int32_t*)out = mjs_get_int32(mjs, *in);
|
||||
}
|
||||
#define JS_ARG_INT32(out) ((_js_arg_decl){out, mjs_is_number, _js_to_int32, "number", NULL, NULL})
|
||||
|
||||
static inline void _js_to_ptr(struct mjs* mjs, mjs_val_t* in, void* out, const void* extra) {
|
||||
UNUSED(extra);
|
||||
*(void**)out = mjs_get_ptr(mjs, *in);
|
||||
}
|
||||
#define JS_ARG_PTR(out) \
|
||||
((_js_arg_decl){out, mjs_is_foreign, _js_to_ptr, "opaque pointer", NULL, NULL})
|
||||
|
||||
static inline void _js_to_string(struct mjs* mjs, mjs_val_t* in, void* out, const void* extra) {
|
||||
UNUSED(extra);
|
||||
*(const char**)out = mjs_get_string(mjs, in, NULL);
|
||||
}
|
||||
#define JS_ARG_STR(out) ((_js_arg_decl){out, mjs_is_string, _js_to_string, "string", NULL, NULL})
|
||||
|
||||
static inline void _js_to_bool(struct mjs* mjs, mjs_val_t* in, void* out, const void* extra) {
|
||||
UNUSED(extra);
|
||||
*(bool*)out = !!mjs_get_bool(mjs, *in);
|
||||
}
|
||||
#define JS_ARG_BOOL(out) ((_js_arg_decl){out, mjs_is_boolean, _js_to_bool, "boolean", NULL, NULL})
|
||||
|
||||
static inline void _js_passthrough(struct mjs* mjs, mjs_val_t* in, void* out, const void* extra) {
|
||||
UNUSED(extra);
|
||||
UNUSED(mjs);
|
||||
*(mjs_val_t*)out = *in;
|
||||
}
|
||||
#define JS_ARG_ANY(out) ((_js_arg_decl){out, NULL, _js_passthrough, "any", NULL, NULL})
|
||||
#define JS_ARG_OBJ(out) ((_js_arg_decl){out, mjs_is_object, _js_passthrough, "any", NULL, NULL})
|
||||
#define JS_ARG_FN(out) \
|
||||
((_js_arg_decl){out, mjs_is_function, _js_passthrough, "function", NULL, NULL})
|
||||
#define JS_ARG_ARR(out) ((_js_arg_decl){out, mjs_is_array, _js_passthrough, "array", NULL, NULL})
|
||||
|
||||
static inline bool _js_validate_struct(struct mjs* mjs, mjs_val_t val, const void* extra) {
|
||||
JsForeignMagic expected_magic = (JsForeignMagic)(size_t)extra;
|
||||
JsForeignMagic struct_magic = *(JsForeignMagic*)mjs_get_ptr(mjs, val);
|
||||
return struct_magic == expected_magic;
|
||||
}
|
||||
#define JS_ARG_STRUCT(type, out) \
|
||||
((_js_arg_decl){ \
|
||||
out, \
|
||||
mjs_is_foreign, \
|
||||
_js_to_ptr, \
|
||||
#type, \
|
||||
_js_validate_struct, \
|
||||
(void*)JsForeignMagic##_##type})
|
||||
|
||||
static inline bool _js_validate_obj_w_struct(struct mjs* mjs, mjs_val_t val, const void* extra) {
|
||||
JsForeignMagic expected_magic = (JsForeignMagic)(size_t)extra;
|
||||
JsForeignMagic struct_magic = *(JsForeignMagic*)JS_GET_INST(mjs, val);
|
||||
return struct_magic == expected_magic;
|
||||
}
|
||||
#define JS_ARG_OBJ_WITH_STRUCT(type, out) \
|
||||
((_js_arg_decl){ \
|
||||
out, \
|
||||
mjs_is_object, \
|
||||
_js_passthrough, \
|
||||
#type, \
|
||||
_js_validate_obj_w_struct, \
|
||||
(void*)JsForeignMagic##_##type})
|
||||
|
||||
static inline bool _js_validate_enum(struct mjs* mjs, mjs_val_t val, const void* extra) {
|
||||
for(const JsEnumMapping* mapping = (JsEnumMapping*)extra + 1; mapping->name; mapping++)
|
||||
if(strcmp(mapping->name, mjs_get_string(mjs, &val, NULL)) == 0) return true;
|
||||
return false;
|
||||
}
|
||||
static inline void
|
||||
_js_convert_enum(struct mjs* mjs, mjs_val_t* val, void* out, const void* extra) {
|
||||
const JsEnumMapping* mapping = (JsEnumMapping*)extra;
|
||||
size_t size = mapping->value; // get enum size from first entry
|
||||
for(mapping++; mapping->name; mapping++) {
|
||||
if(strcmp(mapping->name, mjs_get_string(mjs, val, NULL)) == 0) {
|
||||
if(size == 1)
|
||||
*(uint8_t*)out = mapping->value;
|
||||
else if(size == 2)
|
||||
*(uint16_t*)out = mapping->value;
|
||||
else if(size == 4)
|
||||
*(uint32_t*)out = mapping->value;
|
||||
else if(size == 8)
|
||||
*(uint64_t*)out = mapping->value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// unreachable, thanks to _js_validate_enum
|
||||
}
|
||||
#define JS_ARG_ENUM(var_name, name) \
|
||||
((_js_arg_decl){ \
|
||||
&var_name, \
|
||||
mjs_is_string, \
|
||||
_js_convert_enum, \
|
||||
name " enum", \
|
||||
_js_validate_enum, \
|
||||
var_name##_mapping})
|
||||
|
||||
static inline bool _js_validate_object(struct mjs* mjs, mjs_val_t val, const void* extra) {
|
||||
for(const JsObjectMapping* mapping = (JsObjectMapping*)extra; mapping->name; mapping++)
|
||||
if(mjs_get(mjs, val, mapping->name, ~0) == MJS_UNDEFINED) return false;
|
||||
return true;
|
||||
}
|
||||
static inline void
|
||||
_js_convert_object(struct mjs* mjs, mjs_val_t* val, void* out, const void* extra) {
|
||||
const JsObjectMapping* mapping = (JsObjectMapping*)extra;
|
||||
for(; mapping->name; mapping++) {
|
||||
mjs_val_t field_val = mjs_get(mjs, *val, mapping->name, ~0);
|
||||
*(mjs_val_t*)((uint8_t*)out + mapping->offset) = field_val;
|
||||
}
|
||||
}
|
||||
#define JS_ARG_OBJECT(var_name, name) \
|
||||
((_js_arg_decl){ \
|
||||
&var_name, \
|
||||
mjs_is_object, \
|
||||
_js_convert_object, \
|
||||
name " object", \
|
||||
_js_validate_object, \
|
||||
var_name##_mapping})
|
||||
|
||||
/**
|
||||
* @brief Validates and converts a JS value with a declarative interface
|
||||
*
|
||||
* Example: `int32_t my_value; JS_CONVERT_OR_RETURN(mjs, &mjs_val, JS_ARG_INT32(&my_value), "value source");`
|
||||
*
|
||||
* @warning This macro executes `return;` by design in case of a validation failure
|
||||
*/
|
||||
#define JS_CONVERT_OR_RETURN(mjs, value, decl, source, ...) \
|
||||
if(decl.validator) \
|
||||
if(!decl.validator(*value)) \
|
||||
JS_ERROR_AND_RETURN( \
|
||||
mjs, \
|
||||
MJS_BAD_ARGS_ERROR, \
|
||||
source ": expected %s", \
|
||||
##__VA_ARGS__, \
|
||||
decl.expected_type); \
|
||||
if(decl.extended_validator) \
|
||||
if(!decl.extended_validator(mjs, *value, decl.extra_data)) \
|
||||
JS_ERROR_AND_RETURN( \
|
||||
mjs, \
|
||||
MJS_BAD_ARGS_ERROR, \
|
||||
source ": expected %s", \
|
||||
##__VA_ARGS__, \
|
||||
decl.expected_type); \
|
||||
decl.converter(mjs, value, decl.out, decl.extra_data);
|
||||
|
||||
//-V:JS_FETCH_ARGS_OR_RETURN:1008
|
||||
/**
|
||||
* @brief Fetches and validates the arguments passed to a JS function
|
||||
*
|
||||
* Example: `int32_t my_arg; JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_INT32(&my_arg));`
|
||||
*
|
||||
* @warning This macro executes `return;` by design in case of an argument count
|
||||
* mismatch or a validation failure
|
||||
*/
|
||||
#define JS_FETCH_ARGS_OR_RETURN(mjs, arg_operator, ...) \
|
||||
_js_arg_decl _js_args[] = {__VA_ARGS__}; \
|
||||
int _js_arg_cnt = COUNT_OF(_js_args); \
|
||||
mjs_val_t _js_arg_vals[_js_arg_cnt]; \
|
||||
if(!(mjs_nargs(mjs) arg_operator _js_arg_cnt)) \
|
||||
JS_ERROR_AND_RETURN( \
|
||||
mjs, \
|
||||
MJS_BAD_ARGS_ERROR, \
|
||||
"expected %s%d arguments, got %d", \
|
||||
#arg_operator, \
|
||||
_js_arg_cnt, \
|
||||
mjs_nargs(mjs)); \
|
||||
for(int _i = 0; _i < _js_arg_cnt; _i++) { \
|
||||
_js_arg_vals[_i] = mjs_arg(mjs, _i); \
|
||||
JS_CONVERT_OR_RETURN(mjs, &_js_arg_vals[_i], _js_args[_i], "argument %d", _i); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepends an error, sets the JS return value to `undefined` and returns
|
||||
* from the C function
|
||||
@@ -358,3 +142,7 @@ void js_does_sdk_support(struct mjs* mjs);
|
||||
* @brief `checkSdkFeatures` function
|
||||
*/
|
||||
void js_check_sdk_features(struct mjs* mjs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -198,18 +198,15 @@ static void js_require(struct mjs* mjs) {
|
||||
}
|
||||
|
||||
static void js_parse_int(struct mjs* mjs) {
|
||||
const char* str;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_AT_LEAST, JS_ARG_STR(&str));
|
||||
static const JsValueDeclaration js_parse_int_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeString),
|
||||
JS_VALUE_SIMPLE_W_DEFAULT(JsValueTypeInt32, int32_val, 10),
|
||||
};
|
||||
static const JsValueArguments js_parse_int_args = JS_VALUE_ARGS(js_parse_int_arg_list);
|
||||
|
||||
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);
|
||||
}
|
||||
const char* str;
|
||||
int32_t base;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_parse_int_args, &str, &base);
|
||||
|
||||
int32_t num;
|
||||
if(strint_to_int32(str, NULL, &num, base) != StrintParseNoError) {
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
#include <mjs_primitive_public.h>
|
||||
#include <mjs_array_buf_public.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define INST_PROP_NAME "_"
|
||||
|
||||
typedef enum {
|
||||
@@ -23,3 +27,7 @@ bool js_delay_with_flags(struct mjs* mjs, uint32_t time);
|
||||
void js_flags_set(struct mjs* mjs, uint32_t flags);
|
||||
|
||||
uint32_t js_flags_wait(struct mjs* mjs, uint32_t flags, uint32_t timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -144,10 +144,16 @@ static void js_event_loop_subscribe(struct mjs* mjs) {
|
||||
JsEventLoop* module = JS_GET_CONTEXT(mjs);
|
||||
|
||||
// get arguments
|
||||
static const JsValueDeclaration js_loop_subscribe_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeRawPointer),
|
||||
JS_VALUE_SIMPLE(JsValueTypeFunction),
|
||||
};
|
||||
static const JsValueArguments js_loop_subscribe_args =
|
||||
JS_VALUE_ARGS(js_loop_subscribe_arg_list);
|
||||
|
||||
JsEventLoopContract* contract;
|
||||
mjs_val_t callback;
|
||||
JS_FETCH_ARGS_OR_RETURN(
|
||||
mjs, JS_AT_LEAST, JS_ARG_STRUCT(JsEventLoopContract, &contract), JS_ARG_FN(&callback));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_loop_subscribe_args, &contract, &callback);
|
||||
|
||||
// create subscription object
|
||||
JsEventLoopSubscription* subscription = malloc(sizeof(JsEventLoopSubscription));
|
||||
@@ -242,20 +248,22 @@ static void js_event_loop_stop(struct mjs* mjs) {
|
||||
* event
|
||||
*/
|
||||
static void js_event_loop_timer(struct mjs* mjs) {
|
||||
// get arguments
|
||||
const char* mode_str;
|
||||
int32_t interval;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&mode_str), JS_ARG_INT32(&interval));
|
||||
JsEventLoop* module = JS_GET_CONTEXT(mjs);
|
||||
static const JsValueEnumVariant js_loop_timer_mode_variants[] = {
|
||||
{"periodic", FuriEventLoopTimerTypePeriodic},
|
||||
{"oneshot", FuriEventLoopTimerTypeOnce},
|
||||
};
|
||||
|
||||
static const JsValueDeclaration js_loop_timer_arg_list[] = {
|
||||
JS_VALUE_ENUM(FuriEventLoopTimerType, js_loop_timer_mode_variants),
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
};
|
||||
static const JsValueArguments js_loop_timer_args = JS_VALUE_ARGS(js_loop_timer_arg_list);
|
||||
|
||||
FuriEventLoopTimerType mode;
|
||||
if(strcasecmp(mode_str, "periodic") == 0) {
|
||||
mode = FuriEventLoopTimerTypePeriodic;
|
||||
} else if(strcasecmp(mode_str, "oneshot") == 0) {
|
||||
mode = FuriEventLoopTimerTypeOnce;
|
||||
} else {
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "argument 0: unknown mode");
|
||||
}
|
||||
int32_t interval;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_loop_timer_args, &mode, &interval);
|
||||
|
||||
JsEventLoop* module = JS_GET_CONTEXT(mjs);
|
||||
|
||||
// make timer contract
|
||||
JsEventLoopContract* contract = malloc(sizeof(JsEventLoopContract));
|
||||
@@ -293,8 +301,14 @@ static mjs_val_t
|
||||
*/
|
||||
static void js_event_loop_queue_send(struct mjs* mjs) {
|
||||
// get arguments
|
||||
static const JsValueDeclaration js_loop_q_send_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeAny),
|
||||
};
|
||||
static const JsValueArguments js_loop_q_send_args = JS_VALUE_ARGS(js_loop_q_send_arg_list);
|
||||
|
||||
mjs_val_t message;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_ANY(&message));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_loop_q_send_args, &message);
|
||||
|
||||
JsEventLoopContract* contract = JS_GET_CONTEXT(mjs);
|
||||
|
||||
// send message
|
||||
@@ -311,8 +325,14 @@ static void js_event_loop_queue_send(struct mjs* mjs) {
|
||||
*/
|
||||
static void js_event_loop_queue(struct mjs* mjs) {
|
||||
// get arguments
|
||||
static const JsValueDeclaration js_loop_q_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
};
|
||||
static const JsValueArguments js_loop_q_args = JS_VALUE_ARGS(js_loop_q_arg_list);
|
||||
|
||||
int32_t length;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_INT32(&length));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_loop_q_args, &length);
|
||||
|
||||
JsEventLoop* module = JS_GET_CONTEXT(mjs);
|
||||
|
||||
// make queue contract
|
||||
|
||||
@@ -54,83 +54,114 @@ static void js_gpio_int_cb(void* arg) {
|
||||
* ```
|
||||
*/
|
||||
static void js_gpio_init(struct mjs* mjs) {
|
||||
// deconstruct mode object
|
||||
mjs_val_t mode_arg;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_OBJ(&mode_arg));
|
||||
mjs_val_t direction_arg = mjs_get(mjs, mode_arg, "direction", ~0);
|
||||
mjs_val_t out_mode_arg = mjs_get(mjs, mode_arg, "outMode", ~0);
|
||||
mjs_val_t in_mode_arg = mjs_get(mjs, mode_arg, "inMode", ~0);
|
||||
mjs_val_t edge_arg = mjs_get(mjs, mode_arg, "edge", ~0);
|
||||
mjs_val_t pull_arg = mjs_get(mjs, mode_arg, "pull", ~0);
|
||||
// direction variants
|
||||
typedef enum {
|
||||
JsGpioDirectionIn,
|
||||
JsGpioDirectionOut,
|
||||
} JsGpioDirection;
|
||||
static const JsValueEnumVariant js_gpio_direction_variants[] = {
|
||||
{"in", JsGpioDirectionIn},
|
||||
{"out", JsGpioDirectionOut},
|
||||
};
|
||||
static const JsValueDeclaration js_gpio_direction =
|
||||
JS_VALUE_ENUM(JsGpioDirection, js_gpio_direction_variants);
|
||||
|
||||
// get strings
|
||||
const char* direction = mjs_get_string(mjs, &direction_arg, NULL);
|
||||
const char* out_mode = mjs_get_string(mjs, &out_mode_arg, NULL);
|
||||
const char* in_mode = mjs_get_string(mjs, &in_mode_arg, NULL);
|
||||
const char* edge = mjs_get_string(mjs, &edge_arg, NULL);
|
||||
const char* pull = mjs_get_string(mjs, &pull_arg, NULL);
|
||||
if(!direction)
|
||||
JS_ERROR_AND_RETURN(
|
||||
mjs, MJS_BAD_ARGS_ERROR, "Expected string in \"direction\" field of mode object");
|
||||
if(!out_mode) out_mode = "open_drain";
|
||||
if(!in_mode) in_mode = "plain_digital";
|
||||
if(!edge) edge = "rising";
|
||||
// inMode variants
|
||||
typedef enum {
|
||||
JsGpioInModeAnalog = (0 << 0),
|
||||
JsGpioInModePlainDigital = (1 << 0),
|
||||
JsGpioInModeInterrupt = (2 << 0),
|
||||
JsGpioInModeEvent = (3 << 0),
|
||||
} JsGpioInMode;
|
||||
static const JsValueEnumVariant js_gpio_in_mode_variants[] = {
|
||||
{"analog", JsGpioInModeAnalog},
|
||||
{"plain_digital", JsGpioInModePlainDigital},
|
||||
{"interrupt", JsGpioInModeInterrupt},
|
||||
{"event", JsGpioInModeEvent},
|
||||
};
|
||||
static const JsValueDeclaration js_gpio_in_mode =
|
||||
JS_VALUE_ENUM_W_DEFAULT(JsGpioInMode, js_gpio_in_mode_variants, JsGpioInModePlainDigital);
|
||||
|
||||
// outMode variants
|
||||
typedef enum {
|
||||
JsGpioOutModePushPull,
|
||||
JsGpioOutModeOpenDrain,
|
||||
} JsGpioOutMode;
|
||||
static const JsValueEnumVariant js_gpio_out_mode_variants[] = {
|
||||
{"push_pull", JsGpioOutModePushPull},
|
||||
{"open_drain", JsGpioOutModeOpenDrain},
|
||||
};
|
||||
static const JsValueDeclaration js_gpio_out_mode =
|
||||
JS_VALUE_ENUM_W_DEFAULT(JsGpioOutMode, js_gpio_out_mode_variants, JsGpioOutModeOpenDrain);
|
||||
|
||||
// edge variants
|
||||
typedef enum {
|
||||
JsGpioEdgeRising = (0 << 2),
|
||||
JsGpioEdgeFalling = (1 << 2),
|
||||
JsGpioEdgeBoth = (2 << 2),
|
||||
} JsGpioEdge;
|
||||
static const JsValueEnumVariant js_gpio_edge_variants[] = {
|
||||
{"rising", JsGpioEdgeRising},
|
||||
{"falling", JsGpioEdgeFalling},
|
||||
{"both", JsGpioEdgeBoth},
|
||||
};
|
||||
static const JsValueDeclaration js_gpio_edge =
|
||||
JS_VALUE_ENUM_W_DEFAULT(JsGpioEdge, js_gpio_edge_variants, JsGpioEdgeRising);
|
||||
|
||||
// pull variants
|
||||
static const JsValueEnumVariant js_gpio_pull_variants[] = {
|
||||
{"up", GpioPullUp},
|
||||
{"down", GpioPullDown},
|
||||
};
|
||||
static const JsValueDeclaration js_gpio_pull =
|
||||
JS_VALUE_ENUM_W_DEFAULT(GpioPull, js_gpio_pull_variants, GpioPullNo);
|
||||
|
||||
// complete mode object
|
||||
static const JsValueObjectField js_gpio_mode_object_fields[] = {
|
||||
{"direction", &js_gpio_direction},
|
||||
{"inMode", &js_gpio_in_mode},
|
||||
{"outMode", &js_gpio_out_mode},
|
||||
{"edge", &js_gpio_edge},
|
||||
{"pull", &js_gpio_pull},
|
||||
};
|
||||
|
||||
// function args
|
||||
static const JsValueDeclaration js_gpio_init_arg_list[] = {
|
||||
JS_VALUE_OBJECT_W_DEFAULTS(js_gpio_mode_object_fields),
|
||||
};
|
||||
static const JsValueArguments js_gpio_init_args = JS_VALUE_ARGS(js_gpio_init_arg_list);
|
||||
|
||||
JsGpioDirection direction;
|
||||
JsGpioInMode in_mode;
|
||||
JsGpioOutMode out_mode;
|
||||
JsGpioEdge edge;
|
||||
GpioPull pull;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(
|
||||
mjs, &js_gpio_init_args, &direction, &in_mode, &out_mode, &edge, &pull);
|
||||
|
||||
// convert strings to mode
|
||||
GpioMode mode;
|
||||
if(strcmp(direction, "out") == 0) {
|
||||
if(strcmp(out_mode, "push_pull") == 0)
|
||||
mode = GpioModeOutputPushPull;
|
||||
else if(strcmp(out_mode, "open_drain") == 0)
|
||||
mode = GpioModeOutputOpenDrain;
|
||||
else
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "invalid outMode");
|
||||
} else if(strcmp(direction, "in") == 0) {
|
||||
if(strcmp(in_mode, "analog") == 0) {
|
||||
mode = GpioModeAnalog;
|
||||
} else if(strcmp(in_mode, "plain_digital") == 0) {
|
||||
mode = GpioModeInput;
|
||||
} else if(strcmp(in_mode, "interrupt") == 0) {
|
||||
if(strcmp(edge, "rising") == 0)
|
||||
mode = GpioModeInterruptRise;
|
||||
else if(strcmp(edge, "falling") == 0)
|
||||
mode = GpioModeInterruptFall;
|
||||
else if(strcmp(edge, "both") == 0)
|
||||
mode = GpioModeInterruptRiseFall;
|
||||
else
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "invalid edge");
|
||||
} else if(strcmp(in_mode, "event") == 0) {
|
||||
if(strcmp(edge, "rising") == 0)
|
||||
mode = GpioModeEventRise;
|
||||
else if(strcmp(edge, "falling") == 0)
|
||||
mode = GpioModeEventFall;
|
||||
else if(strcmp(edge, "both") == 0)
|
||||
mode = GpioModeEventRiseFall;
|
||||
else
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "invalid edge");
|
||||
if(direction == JsGpioDirectionOut) {
|
||||
static const GpioMode js_gpio_out_mode_lut[] = {
|
||||
[JsGpioOutModePushPull] = GpioModeOutputPushPull,
|
||||
[JsGpioOutModeOpenDrain] = GpioModeOutputOpenDrain,
|
||||
};
|
||||
mode = js_gpio_out_mode_lut[out_mode];
|
||||
} else {
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "invalid inMode");
|
||||
}
|
||||
} else {
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "invalid direction");
|
||||
static const GpioMode js_gpio_in_mode_lut[] = {
|
||||
[JsGpioInModeAnalog] = GpioModeAnalog,
|
||||
[JsGpioInModePlainDigital] = GpioModeInput,
|
||||
[JsGpioInModeInterrupt | JsGpioEdgeRising] = GpioModeInterruptRise,
|
||||
[JsGpioInModeInterrupt | JsGpioEdgeFalling] = GpioModeInterruptFall,
|
||||
[JsGpioInModeInterrupt | JsGpioEdgeBoth] = GpioModeInterruptRiseFall,
|
||||
[JsGpioInModeEvent | JsGpioEdgeRising] = GpioModeEventRise,
|
||||
[JsGpioInModeEvent | JsGpioEdgeFalling] = GpioModeEventFall,
|
||||
[JsGpioInModeEvent | JsGpioEdgeBoth] = GpioModeEventRiseFall,
|
||||
};
|
||||
mode = js_gpio_in_mode_lut[in_mode | edge];
|
||||
}
|
||||
|
||||
// convert pull
|
||||
GpioPull pull_mode;
|
||||
if(!pull) {
|
||||
pull_mode = GpioPullNo;
|
||||
} else if(strcmp(pull, "up") == 0) {
|
||||
pull_mode = GpioPullUp;
|
||||
} else if(strcmp(pull, "down") == 0) {
|
||||
pull_mode = GpioPullDown;
|
||||
} else {
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "invalid pull");
|
||||
}
|
||||
|
||||
// init GPIO
|
||||
JsGpioPinInst* manager_data = JS_GET_CONTEXT(mjs);
|
||||
furi_hal_gpio_init(manager_data->pin, mode, pull_mode, GpioSpeedVeryHigh);
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
furi_hal_gpio_init(manager_data->pin, mode, pull, GpioSpeedVeryHigh);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,8 +177,13 @@ static void js_gpio_init(struct mjs* mjs) {
|
||||
* ```
|
||||
*/
|
||||
static void js_gpio_write(struct mjs* mjs) {
|
||||
static const JsValueDeclaration js_gpio_write_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeBool),
|
||||
};
|
||||
static const JsValueArguments js_gpio_write_args = JS_VALUE_ARGS(js_gpio_write_arg_list);
|
||||
bool level;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_BOOL(&level));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_gpio_write_args, &level);
|
||||
|
||||
JsGpioPinInst* manager_data = JS_GET_CONTEXT(mjs);
|
||||
furi_hal_gpio_write(manager_data->pin, level);
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
@@ -261,9 +297,16 @@ static void js_gpio_is_pwm_supported(struct mjs* mjs) {
|
||||
* ```
|
||||
*/
|
||||
static void js_gpio_pwm_write(struct mjs* mjs) {
|
||||
JsGpioPinInst* manager_data = JS_GET_CONTEXT(mjs);
|
||||
static const JsValueDeclaration js_gpio_pwm_write_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
};
|
||||
static const JsValueArguments js_gpio_pwm_write_args =
|
||||
JS_VALUE_ARGS(js_gpio_pwm_write_arg_list);
|
||||
int32_t frequency, duty;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_INT32(&frequency), JS_ARG_INT32(&duty));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_gpio_pwm_write_args, &frequency, &duty);
|
||||
|
||||
JsGpioPinInst* manager_data = JS_GET_CONTEXT(mjs);
|
||||
if(manager_data->pwm_output == FuriHalPwmOutputIdNone) {
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "PWM is not supported on this pin");
|
||||
}
|
||||
@@ -326,8 +369,13 @@ static void js_gpio_pwm_stop(struct mjs* mjs) {
|
||||
* ```
|
||||
*/
|
||||
static void js_gpio_get(struct mjs* mjs) {
|
||||
static const JsValueDeclaration js_gpio_get_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeAny),
|
||||
};
|
||||
static const JsValueArguments js_gpio_get_args = JS_VALUE_ARGS(js_gpio_get_arg_list);
|
||||
mjs_val_t name_arg;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_ANY(&name_arg));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_gpio_get_args, &name_arg);
|
||||
|
||||
const char* name_string = mjs_get_string(mjs, &name_arg, NULL);
|
||||
const GpioPinRecord* pin_record = NULL;
|
||||
|
||||
|
||||
@@ -3,8 +3,14 @@
|
||||
#include <assets_icons.h>
|
||||
|
||||
static void js_gui_file_picker_pick_file(struct mjs* mjs) {
|
||||
static const JsValueDeclaration js_picker_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeString),
|
||||
JS_VALUE_SIMPLE(JsValueTypeString),
|
||||
};
|
||||
static const JsValueArguments js_picker_args = JS_VALUE_ARGS(js_picker_arg_list);
|
||||
|
||||
const char *base_path, *extension;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&base_path), JS_ARG_STR(&extension));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_picker_args, &base_path, &extension);
|
||||
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
const DialogsFileBrowserOptions browser_options = {
|
||||
|
||||
@@ -39,9 +39,14 @@ typedef struct {
|
||||
FxbmIconWrapperList_t fxbm_list;
|
||||
} JsGuiIconInst;
|
||||
|
||||
static const JsValueDeclaration js_icon_get_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeString),
|
||||
};
|
||||
static const JsValueArguments js_icon_get_args = JS_VALUE_ARGS(js_icon_get_arg_list);
|
||||
|
||||
static void js_gui_icon_get_builtin(struct mjs* mjs) {
|
||||
const char* icon_name;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&icon_name));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_icon_get_args, &icon_name);
|
||||
|
||||
for(size_t i = 0; i < COUNT_OF(builtin_icons); i++) {
|
||||
if(strcmp(icon_name, builtin_icons[i].name) == 0) {
|
||||
@@ -55,7 +60,7 @@ static void js_gui_icon_get_builtin(struct mjs* mjs) {
|
||||
|
||||
static void js_gui_icon_load_fxbm(struct mjs* mjs) {
|
||||
const char* fxbm_path;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&fxbm_path));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_icon_get_args, &fxbm_path);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(storage);
|
||||
|
||||
@@ -68,8 +68,14 @@ static bool js_gui_vd_nav_callback(void* context) {
|
||||
* @brief `viewDispatcher.sendCustom`
|
||||
*/
|
||||
static void js_gui_vd_send_custom(struct mjs* mjs) {
|
||||
static const JsValueDeclaration js_gui_vd_send_custom_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
};
|
||||
static const JsValueArguments js_gui_vd_send_custom_args =
|
||||
JS_VALUE_ARGS(js_gui_vd_send_custom_arg_list);
|
||||
|
||||
int32_t event;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_INT32(&event));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_gui_vd_send_custom_args, &event);
|
||||
|
||||
JsGui* module = JS_GET_CONTEXT(mjs);
|
||||
view_dispatcher_send_custom_event(module->dispatcher, (uint32_t)event);
|
||||
@@ -79,15 +85,25 @@ static void js_gui_vd_send_custom(struct mjs* mjs) {
|
||||
* @brief `viewDispatcher.sendTo`
|
||||
*/
|
||||
static void js_gui_vd_send_to(struct mjs* mjs) {
|
||||
enum {
|
||||
SendDirToFront,
|
||||
SendDirToBack,
|
||||
} send_direction;
|
||||
JS_ENUM_MAP(send_direction, {"front", SendDirToFront}, {"back", SendDirToBack});
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_ENUM(send_direction, "SendDirection"));
|
||||
typedef enum {
|
||||
JsSendDirToFront,
|
||||
JsSendDirToBack,
|
||||
} JsSendDir;
|
||||
static const JsValueEnumVariant js_send_dir_variants[] = {
|
||||
{"front", JsSendDirToFront},
|
||||
{"back", JsSendDirToBack},
|
||||
};
|
||||
static const JsValueDeclaration js_gui_vd_send_to_arg_list[] = {
|
||||
JS_VALUE_ENUM(JsSendDir, js_send_dir_variants),
|
||||
};
|
||||
static const JsValueArguments js_gui_vd_send_to_args =
|
||||
JS_VALUE_ARGS(js_gui_vd_send_to_arg_list);
|
||||
|
||||
JsSendDir send_direction;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_gui_vd_send_to_args, &send_direction);
|
||||
|
||||
JsGui* module = JS_GET_CONTEXT(mjs);
|
||||
if(send_direction == SendDirToBack) {
|
||||
if(send_direction == JsSendDirToBack) {
|
||||
view_dispatcher_send_to_back(module->dispatcher);
|
||||
} else {
|
||||
view_dispatcher_send_to_front(module->dispatcher);
|
||||
@@ -98,8 +114,15 @@ static void js_gui_vd_send_to(struct mjs* mjs) {
|
||||
* @brief `viewDispatcher.switchTo`
|
||||
*/
|
||||
static void js_gui_vd_switch_to(struct mjs* mjs) {
|
||||
static const JsValueDeclaration js_gui_vd_switch_to_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeAny),
|
||||
};
|
||||
static const JsValueArguments js_gui_vd_switch_to_args =
|
||||
JS_VALUE_ARGS(js_gui_vd_switch_to_arg_list);
|
||||
|
||||
mjs_val_t view;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_OBJ(&view));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_gui_vd_switch_to_args, &view);
|
||||
|
||||
JsGuiViewData* view_data = JS_GET_INST(mjs, view);
|
||||
mjs_val_t vd_obj = mjs_get_this(mjs);
|
||||
JsGui* module = JS_GET_INST(mjs, vd_obj);
|
||||
@@ -267,9 +290,16 @@ static bool
|
||||
* @brief `View.set`
|
||||
*/
|
||||
static void js_gui_view_set(struct mjs* mjs) {
|
||||
static const JsValueDeclaration js_gui_view_set_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeString),
|
||||
JS_VALUE_SIMPLE(JsValueTypeAny),
|
||||
};
|
||||
static const JsValueArguments js_gui_view_set_args = JS_VALUE_ARGS(js_gui_view_set_arg_list);
|
||||
|
||||
const char* name;
|
||||
mjs_val_t value;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&name), JS_ARG_ANY(&value));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_gui_view_set_args, &name, &value);
|
||||
|
||||
JsGuiViewData* data = JS_GET_CONTEXT(mjs);
|
||||
bool success = js_gui_view_assign(mjs, name, value, data);
|
||||
UNUSED(success);
|
||||
@@ -280,12 +310,19 @@ static void js_gui_view_set(struct mjs* mjs) {
|
||||
* @brief `View.addChild`
|
||||
*/
|
||||
static void js_gui_view_add_child(struct mjs* mjs) {
|
||||
static const JsValueDeclaration js_gui_view_add_child_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeAny),
|
||||
};
|
||||
static const JsValueArguments js_gui_view_add_child_args =
|
||||
JS_VALUE_ARGS(js_gui_view_add_child_arg_list);
|
||||
|
||||
mjs_val_t child;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_gui_view_add_child_args, &child);
|
||||
|
||||
JsGuiViewData* data = JS_GET_CONTEXT(mjs);
|
||||
if(!data->descriptor->add_child || !data->descriptor->reset_children)
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "this View can't have children");
|
||||
|
||||
mjs_val_t child;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_ANY(&child));
|
||||
bool success = data->descriptor->add_child(mjs, data->specific_view, data->custom_data, child);
|
||||
UNUSED(success);
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
@@ -307,12 +344,19 @@ static void js_gui_view_reset_children(struct mjs* mjs) {
|
||||
* @brief `View.setChildren`
|
||||
*/
|
||||
static void js_gui_view_set_children(struct mjs* mjs) {
|
||||
static const JsValueDeclaration js_gui_view_set_children_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeAnyArray),
|
||||
};
|
||||
static const JsValueArguments js_gui_view_set_children_args =
|
||||
JS_VALUE_ARGS(js_gui_view_set_children_arg_list);
|
||||
|
||||
mjs_val_t children;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_gui_view_set_children_args, &children);
|
||||
|
||||
JsGuiViewData* data = JS_GET_CONTEXT(mjs);
|
||||
if(!data->descriptor->add_child || !data->descriptor->reset_children)
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "this View can't have children");
|
||||
|
||||
mjs_val_t children;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_ARR(&children));
|
||||
js_gui_view_internal_set_children(mjs, children, data);
|
||||
}
|
||||
|
||||
@@ -365,7 +409,6 @@ static mjs_val_t js_gui_make_view(struct mjs* mjs, const JsViewDescriptor* descr
|
||||
* @brief `ViewFactory.make`
|
||||
*/
|
||||
static void js_gui_vf_make(struct mjs* mjs) {
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY); // 0 args
|
||||
const JsViewDescriptor* descriptor = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, js_gui_make_view(mjs, descriptor));
|
||||
}
|
||||
@@ -374,8 +417,15 @@ static void js_gui_vf_make(struct mjs* mjs) {
|
||||
* @brief `ViewFactory.makeWith`
|
||||
*/
|
||||
static void js_gui_vf_make_with(struct mjs* mjs) {
|
||||
mjs_val_t props;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_AT_LEAST, JS_ARG_OBJ(&props));
|
||||
static const JsValueDeclaration js_gui_vf_make_with_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeAnyObject),
|
||||
JS_VALUE_SIMPLE(JsValueTypeAny),
|
||||
};
|
||||
static const JsValueArguments js_gui_vf_make_with_args =
|
||||
JS_VALUE_ARGS(js_gui_vf_make_with_arg_list);
|
||||
|
||||
mjs_val_t props, children;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_gui_vf_make_with_args, &props, &children);
|
||||
const JsViewDescriptor* descriptor = JS_GET_CONTEXT(mjs);
|
||||
|
||||
// make the object like normal
|
||||
@@ -396,14 +446,10 @@ static void js_gui_vf_make_with(struct mjs* mjs) {
|
||||
}
|
||||
|
||||
// assign children
|
||||
if(mjs_nargs(mjs) >= 2) {
|
||||
if(mjs_is_array(children)) {
|
||||
if(!data->descriptor->add_child || !data->descriptor->reset_children)
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "this View can't have children");
|
||||
|
||||
mjs_val_t children = mjs_arg(mjs, 1);
|
||||
if(!mjs_is_array(children))
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_BAD_ARGS_ERROR, "argument 1: expected array");
|
||||
|
||||
if(!js_gui_view_internal_set_children(mjs, children, data)) return;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,60 +35,62 @@ static void
|
||||
}
|
||||
|
||||
static void js_serial_setup(struct mjs* mjs) {
|
||||
FuriHalSerialId serial_id;
|
||||
int32_t baudrate;
|
||||
JS_ENUM_MAP(serial_id, {"lpuart", FuriHalSerialIdLpuart}, {"usart", FuriHalSerialIdUsart});
|
||||
JS_FETCH_ARGS_OR_RETURN(
|
||||
mjs, JS_AT_LEAST, JS_ARG_ENUM(serial_id, "SerialId"), JS_ARG_INT32(&baudrate));
|
||||
static const JsValueEnumVariant js_serial_id_variants[] = {
|
||||
{"lpuart", FuriHalSerialIdLpuart},
|
||||
{"usart", FuriHalSerialIdUsart},
|
||||
};
|
||||
|
||||
FuriHalSerialDataBits data_bits = FuriHalSerialDataBits8;
|
||||
FuriHalSerialParity parity = FuriHalSerialParityNone;
|
||||
FuriHalSerialStopBits stop_bits = FuriHalSerialStopBits1;
|
||||
if(mjs_nargs(mjs) > 2) {
|
||||
struct framing {
|
||||
mjs_val_t data_bits;
|
||||
mjs_val_t parity;
|
||||
mjs_val_t stop_bits;
|
||||
} framing;
|
||||
JS_OBJ_MAP(
|
||||
framing,
|
||||
{"dataBits", offsetof(struct framing, data_bits)},
|
||||
{"parity", offsetof(struct framing, parity)},
|
||||
{"stopBits", offsetof(struct framing, stop_bits)});
|
||||
JS_ENUM_MAP(
|
||||
data_bits,
|
||||
static const JsValueEnumVariant js_serial_data_bit_variants[] = {
|
||||
{"6", FuriHalSerialDataBits6},
|
||||
{"7", FuriHalSerialDataBits7},
|
||||
{"8", FuriHalSerialDataBits8},
|
||||
{"9", FuriHalSerialDataBits9});
|
||||
JS_ENUM_MAP(
|
||||
parity,
|
||||
{"9", FuriHalSerialDataBits9},
|
||||
};
|
||||
static const JsValueDeclaration js_serial_data_bits = JS_VALUE_ENUM_W_DEFAULT(
|
||||
FuriHalSerialDataBits, js_serial_data_bit_variants, FuriHalSerialDataBits8);
|
||||
|
||||
static const JsValueEnumVariant js_serial_parity_variants[] = {
|
||||
{"none", FuriHalSerialParityNone},
|
||||
{"even", FuriHalSerialParityEven},
|
||||
{"odd", FuriHalSerialParityOdd});
|
||||
JS_ENUM_MAP(
|
||||
stop_bits,
|
||||
{"odd", FuriHalSerialParityOdd},
|
||||
};
|
||||
static const JsValueDeclaration js_serial_parity = JS_VALUE_ENUM_W_DEFAULT(
|
||||
FuriHalSerialParity, js_serial_parity_variants, FuriHalSerialParityNone);
|
||||
|
||||
static const JsValueEnumVariant js_serial_stop_bit_variants[] = {
|
||||
{"0.5", FuriHalSerialStopBits0_5},
|
||||
{"1", FuriHalSerialStopBits1},
|
||||
{"1.5", FuriHalSerialStopBits1_5},
|
||||
{"2", FuriHalSerialStopBits2});
|
||||
mjs_val_t framing_obj = mjs_arg(mjs, 2);
|
||||
JS_CONVERT_OR_RETURN(mjs, &framing_obj, JS_ARG_OBJECT(framing, "Framing"), "argument 2");
|
||||
JS_CONVERT_OR_RETURN(
|
||||
mjs, &framing.data_bits, JS_ARG_ENUM(data_bits, "DataBits"), "argument 2: dataBits");
|
||||
JS_CONVERT_OR_RETURN(
|
||||
mjs, &framing.parity, JS_ARG_ENUM(parity, "Parity"), "argument 2: parity");
|
||||
JS_CONVERT_OR_RETURN(
|
||||
mjs, &framing.stop_bits, JS_ARG_ENUM(stop_bits, "StopBits"), "argument 2: stopBits");
|
||||
}
|
||||
{"2", FuriHalSerialStopBits2},
|
||||
};
|
||||
static const JsValueDeclaration js_serial_stop_bits = JS_VALUE_ENUM_W_DEFAULT(
|
||||
FuriHalSerialStopBits, js_serial_stop_bit_variants, FuriHalSerialStopBits1);
|
||||
|
||||
static const JsValueObjectField js_serial_framing_fields[] = {
|
||||
{"dataBits", &js_serial_data_bits},
|
||||
{"parity", &js_serial_parity},
|
||||
{"stopBits", &js_serial_stop_bits},
|
||||
};
|
||||
|
||||
static const JsValueDeclaration js_serial_setup_arg_list[] = {
|
||||
JS_VALUE_ENUM(FuriHalSerialId, js_serial_id_variants),
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
JS_VALUE_OBJECT_W_DEFAULTS(js_serial_framing_fields),
|
||||
};
|
||||
static const JsValueArguments js_serial_setup_args = JS_VALUE_ARGS(js_serial_setup_arg_list);
|
||||
|
||||
FuriHalSerialId serial_id;
|
||||
int32_t baudrate;
|
||||
FuriHalSerialDataBits data_bits = FuriHalSerialDataBits8;
|
||||
FuriHalSerialParity parity = FuriHalSerialParityNone;
|
||||
FuriHalSerialStopBits stop_bits = FuriHalSerialStopBits1;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(
|
||||
mjs, &js_serial_setup_args, &serial_id, &baudrate, &data_bits, &parity, &stop_bits);
|
||||
|
||||
JsSerialInst* serial = JS_GET_CONTEXT(mjs);
|
||||
|
||||
if(serial->setup_done) {
|
||||
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Serial is already configured");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
if(serial->setup_done)
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_INTERNAL_ERROR, "Serial is already configured");
|
||||
|
||||
expansion_disable(furi_record_open(RECORD_EXPANSION));
|
||||
furi_record_close(RECORD_EXPANSION);
|
||||
@@ -123,28 +125,20 @@ static void js_serial_deinit(JsSerialInst* js_serial) {
|
||||
}
|
||||
|
||||
static void js_serial_end(struct mjs* mjs) {
|
||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||
JsSerialInst* serial = mjs_get_ptr(mjs, obj_inst);
|
||||
JsSerialInst* serial = JS_GET_CONTEXT(mjs);
|
||||
furi_assert(serial);
|
||||
|
||||
if(!serial->setup_done) {
|
||||
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Serial is not configured");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
if(!serial->setup_done)
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_INTERNAL_ERROR, "Serial is not configured");
|
||||
|
||||
js_serial_deinit(serial);
|
||||
}
|
||||
|
||||
static void js_serial_write(struct mjs* mjs) {
|
||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||
JsSerialInst* serial = mjs_get_ptr(mjs, obj_inst);
|
||||
JsSerialInst* serial = JS_GET_CONTEXT(mjs);
|
||||
furi_assert(serial);
|
||||
if(!serial->setup_done) {
|
||||
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Serial is not configured");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
if(!serial->setup_done)
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_INTERNAL_ERROR, "Serial is not configured");
|
||||
|
||||
bool args_correct = true;
|
||||
|
||||
@@ -228,43 +222,20 @@ static size_t js_serial_receive(JsSerialInst* serial, char* buf, size_t len, uin
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static const JsValueDeclaration js_serial_read_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
JS_VALUE_SIMPLE_W_DEFAULT(JsValueTypeInt32, int32_val, INT32_MAX),
|
||||
};
|
||||
static const JsValueArguments js_serial_read_args = JS_VALUE_ARGS(js_serial_read_arg_list);
|
||||
|
||||
static void js_serial_read(struct mjs* mjs) {
|
||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||
JsSerialInst* serial = mjs_get_ptr(mjs, obj_inst);
|
||||
JsSerialInst* serial = JS_GET_CONTEXT(mjs);
|
||||
furi_assert(serial);
|
||||
if(!serial->setup_done) {
|
||||
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Serial is not configured");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
if(!serial->setup_done)
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_INTERNAL_ERROR, "Serial is not configured");
|
||||
|
||||
size_t read_len = 0;
|
||||
uint32_t timeout = FuriWaitForever;
|
||||
|
||||
do {
|
||||
size_t num_args = mjs_nargs(mjs);
|
||||
if(num_args == 1) {
|
||||
mjs_val_t arg = mjs_arg(mjs, 0);
|
||||
if(!mjs_is_number(arg)) {
|
||||
break;
|
||||
}
|
||||
read_len = mjs_get_int32(mjs, arg);
|
||||
} else if(num_args == 2) {
|
||||
mjs_val_t len_arg = mjs_arg(mjs, 0);
|
||||
mjs_val_t timeout_arg = mjs_arg(mjs, 1);
|
||||
if((!mjs_is_number(len_arg)) || (!mjs_is_number(timeout_arg))) {
|
||||
break;
|
||||
}
|
||||
read_len = mjs_get_int32(mjs, len_arg);
|
||||
timeout = mjs_get_int32(mjs, timeout_arg);
|
||||
}
|
||||
} while(0);
|
||||
|
||||
if(read_len == 0) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
int32_t read_len, timeout;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_serial_read_args, &read_len, &timeout);
|
||||
|
||||
char* read_buf = malloc(read_len);
|
||||
size_t bytes_read = js_serial_receive(serial, read_buf, read_len, timeout);
|
||||
@@ -278,37 +249,19 @@ static void js_serial_read(struct mjs* mjs) {
|
||||
}
|
||||
|
||||
static void js_serial_readln(struct mjs* mjs) {
|
||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||
JsSerialInst* serial = mjs_get_ptr(mjs, obj_inst);
|
||||
JsSerialInst* serial = JS_GET_CONTEXT(mjs);
|
||||
furi_assert(serial);
|
||||
if(!serial->setup_done) {
|
||||
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Serial is not configured");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
if(!serial->setup_done)
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_INTERNAL_ERROR, "Serial is not configured");
|
||||
|
||||
bool args_correct = false;
|
||||
uint32_t timeout = FuriWaitForever;
|
||||
static const JsValueDeclaration js_serial_readln_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
};
|
||||
static const JsValueArguments js_serial_readln_args = JS_VALUE_ARGS(js_serial_readln_arg_list);
|
||||
|
||||
do {
|
||||
size_t num_args = mjs_nargs(mjs);
|
||||
if(num_args > 1) {
|
||||
break;
|
||||
} else if(num_args == 1) {
|
||||
mjs_val_t arg = mjs_arg(mjs, 0);
|
||||
if(!mjs_is_number(arg)) {
|
||||
break;
|
||||
}
|
||||
timeout = mjs_get_int32(mjs, arg);
|
||||
}
|
||||
args_correct = true;
|
||||
} while(0);
|
||||
int32_t timeout;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_serial_readln_args, &timeout);
|
||||
|
||||
if(!args_correct) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
FuriString* rx_buf = furi_string_alloc();
|
||||
size_t bytes_read = 0;
|
||||
char read_char = 0;
|
||||
@@ -335,42 +288,13 @@ static void js_serial_readln(struct mjs* mjs) {
|
||||
}
|
||||
|
||||
static void js_serial_read_bytes(struct mjs* mjs) {
|
||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||
JsSerialInst* serial = mjs_get_ptr(mjs, obj_inst);
|
||||
JsSerialInst* serial = JS_GET_CONTEXT(mjs);
|
||||
furi_assert(serial);
|
||||
if(!serial->setup_done) {
|
||||
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Serial is not configured");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
if(!serial->setup_done)
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_INTERNAL_ERROR, "Serial is not configured");
|
||||
|
||||
size_t read_len = 0;
|
||||
uint32_t timeout = FuriWaitForever;
|
||||
|
||||
do {
|
||||
size_t num_args = mjs_nargs(mjs);
|
||||
if(num_args == 1) {
|
||||
mjs_val_t arg = mjs_arg(mjs, 0);
|
||||
if(!mjs_is_number(arg)) {
|
||||
break;
|
||||
}
|
||||
read_len = mjs_get_int32(mjs, arg);
|
||||
} else if(num_args == 2) {
|
||||
mjs_val_t len_arg = mjs_arg(mjs, 0);
|
||||
mjs_val_t timeout_arg = mjs_arg(mjs, 1);
|
||||
if((!mjs_is_number(len_arg)) || (!mjs_is_number(timeout_arg))) {
|
||||
break;
|
||||
}
|
||||
read_len = mjs_get_int32(mjs, len_arg);
|
||||
timeout = mjs_get_int32(mjs, timeout_arg);
|
||||
}
|
||||
} while(0);
|
||||
|
||||
if(read_len == 0) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
int32_t read_len, timeout;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_serial_read_args, &read_len, &timeout);
|
||||
|
||||
char* read_buf = malloc(read_len);
|
||||
size_t bytes_read = js_serial_receive(serial, read_buf, read_len, timeout);
|
||||
@@ -399,27 +323,19 @@ static char* js_serial_receive_any(JsSerialInst* serial, size_t* len, uint32_t t
|
||||
}
|
||||
|
||||
static void js_serial_read_any(struct mjs* mjs) {
|
||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||
JsSerialInst* serial = mjs_get_ptr(mjs, obj_inst);
|
||||
JsSerialInst* serial = JS_GET_CONTEXT(mjs);
|
||||
furi_assert(serial);
|
||||
if(!serial->setup_done) {
|
||||
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Serial is not configured");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
if(!serial->setup_done)
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_INTERNAL_ERROR, "Serial is not configured");
|
||||
|
||||
uint32_t timeout = FuriWaitForever;
|
||||
static const JsValueDeclaration js_serial_read_any_arg_list[] = {
|
||||
JS_VALUE_SIMPLE_W_DEFAULT(JsValueTypeInt32, int32_val, INT32_MAX),
|
||||
};
|
||||
static const JsValueArguments js_serial_read_any_args =
|
||||
JS_VALUE_ARGS(js_serial_read_any_arg_list);
|
||||
|
||||
do {
|
||||
size_t num_args = mjs_nargs(mjs);
|
||||
if(num_args == 1) {
|
||||
mjs_val_t timeout_arg = mjs_arg(mjs, 0);
|
||||
if(!mjs_is_number(timeout_arg)) {
|
||||
break;
|
||||
}
|
||||
timeout = mjs_get_int32(mjs, timeout_arg);
|
||||
}
|
||||
} while(0);
|
||||
int32_t timeout;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_serial_read_any_args, &timeout);
|
||||
|
||||
size_t bytes_read = 0;
|
||||
char* read_buf = js_serial_receive_any(serial, &bytes_read, timeout);
|
||||
@@ -663,16 +579,19 @@ static void* js_serial_create(struct mjs* mjs, mjs_val_t* object, JsModules* mod
|
||||
UNUSED(modules);
|
||||
JsSerialInst* js_serial = malloc(sizeof(JsSerialInst));
|
||||
js_serial->mjs = mjs;
|
||||
|
||||
mjs_val_t serial_obj = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, serial_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, js_serial));
|
||||
mjs_set(mjs, serial_obj, "setup", ~0, MJS_MK_FN(js_serial_setup));
|
||||
mjs_set(mjs, serial_obj, "end", ~0, MJS_MK_FN(js_serial_end));
|
||||
mjs_set(mjs, serial_obj, "write", ~0, MJS_MK_FN(js_serial_write));
|
||||
mjs_set(mjs, serial_obj, "read", ~0, MJS_MK_FN(js_serial_read));
|
||||
mjs_set(mjs, serial_obj, "readln", ~0, MJS_MK_FN(js_serial_readln));
|
||||
mjs_set(mjs, serial_obj, "readBytes", ~0, MJS_MK_FN(js_serial_read_bytes));
|
||||
mjs_set(mjs, serial_obj, "readAny", ~0, MJS_MK_FN(js_serial_read_any));
|
||||
mjs_set(mjs, serial_obj, "expect", ~0, MJS_MK_FN(js_serial_expect));
|
||||
JS_ASSIGN_MULTI(mjs, serial_obj) {
|
||||
JS_FIELD(INST_PROP_NAME, mjs_mk_foreign(mjs, js_serial));
|
||||
JS_FIELD("setup", MJS_MK_FN(js_serial_setup));
|
||||
JS_FIELD("end", MJS_MK_FN(js_serial_end));
|
||||
JS_FIELD("write", MJS_MK_FN(js_serial_write));
|
||||
JS_FIELD("read", MJS_MK_FN(js_serial_read));
|
||||
JS_FIELD("readln", MJS_MK_FN(js_serial_readln));
|
||||
JS_FIELD("readBytes", MJS_MK_FN(js_serial_read_bytes));
|
||||
JS_FIELD("readAny", MJS_MK_FN(js_serial_read_any));
|
||||
JS_FIELD("expect", MJS_MK_FN(js_serial_expect));
|
||||
}
|
||||
*object = serial_obj;
|
||||
|
||||
return js_serial;
|
||||
|
||||
@@ -1,42 +1,79 @@
|
||||
#include "../js_modules.h" // IWYU pragma: keep
|
||||
#include <path.h>
|
||||
|
||||
// ---=== file ops ===---
|
||||
// ==========================
|
||||
// Common argument signatures
|
||||
// ==========================
|
||||
|
||||
static const JsValueDeclaration js_storage_1_int_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
};
|
||||
static const JsValueArguments js_storage_1_int_args = JS_VALUE_ARGS(js_storage_1_int_arg_list);
|
||||
|
||||
static const JsValueDeclaration js_storage_1_str_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeString),
|
||||
};
|
||||
static const JsValueArguments js_storage_1_str_args = JS_VALUE_ARGS(js_storage_1_str_arg_list);
|
||||
|
||||
static const JsValueDeclaration js_storage_2_str_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeString),
|
||||
JS_VALUE_SIMPLE(JsValueTypeString),
|
||||
};
|
||||
static const JsValueArguments js_storage_2_str_args = JS_VALUE_ARGS(js_storage_2_str_arg_list);
|
||||
|
||||
// ======================
|
||||
// File object operations
|
||||
// ======================
|
||||
|
||||
static void js_storage_file_close(struct mjs* mjs) {
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY); // 0 args
|
||||
File* file = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_file_close(file)));
|
||||
}
|
||||
|
||||
static void js_storage_file_is_open(struct mjs* mjs) {
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY); // 0 args
|
||||
File* file = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_file_is_open(file)));
|
||||
}
|
||||
|
||||
static void js_storage_file_read(struct mjs* mjs) {
|
||||
enum {
|
||||
ReadModeAscii,
|
||||
ReadModeBinary,
|
||||
} read_mode;
|
||||
JS_ENUM_MAP(read_mode, {"ascii", ReadModeAscii}, {"binary", ReadModeBinary});
|
||||
typedef enum {
|
||||
JsStorageReadModeAscii,
|
||||
JsStorageReadModeBinary,
|
||||
} JsStorageReadMode;
|
||||
static const JsValueEnumVariant js_storage_read_mode_variants[] = {
|
||||
{"ascii", JsStorageReadModeAscii},
|
||||
{"binary", JsStorageReadModeBinary},
|
||||
};
|
||||
static const JsValueDeclaration js_storage_read_arg_list[] = {
|
||||
JS_VALUE_ENUM(JsStorageReadMode, js_storage_read_mode_variants),
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
};
|
||||
static const JsValueArguments js_storage_read_args = JS_VALUE_ARGS(js_storage_read_arg_list);
|
||||
|
||||
JsStorageReadMode read_mode;
|
||||
int32_t length;
|
||||
JS_FETCH_ARGS_OR_RETURN(
|
||||
mjs, JS_EXACTLY, JS_ARG_ENUM(read_mode, "ReadMode"), JS_ARG_INT32(&length));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_read_args, &read_mode, &length);
|
||||
|
||||
File* file = JS_GET_CONTEXT(mjs);
|
||||
char buffer[length];
|
||||
size_t actually_read = storage_file_read(file, buffer, length);
|
||||
if(read_mode == ReadModeAscii) {
|
||||
if(read_mode == JsStorageReadModeAscii) {
|
||||
mjs_return(mjs, mjs_mk_string(mjs, buffer, actually_read, true));
|
||||
} else if(read_mode == ReadModeBinary) {
|
||||
} else if(read_mode == JsStorageReadModeBinary) {
|
||||
mjs_return(mjs, mjs_mk_array_buf(mjs, buffer, actually_read));
|
||||
}
|
||||
}
|
||||
|
||||
static void js_storage_file_write(struct mjs* mjs) {
|
||||
static const JsValueDeclaration js_storage_file_write_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeAny),
|
||||
};
|
||||
static const JsValueArguments js_storage_file_write_args =
|
||||
JS_VALUE_ARGS(js_storage_file_write_arg_list);
|
||||
|
||||
mjs_val_t data;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_ANY(&data));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_file_write_args, &data);
|
||||
|
||||
const void* buf;
|
||||
size_t len;
|
||||
if(mjs_is_string(data)) {
|
||||
@@ -52,52 +89,58 @@ static void js_storage_file_write(struct mjs* mjs) {
|
||||
|
||||
static void js_storage_file_seek_relative(struct mjs* mjs) {
|
||||
int32_t offset;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_INT32(&offset));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_1_int_args, &offset);
|
||||
File* file = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_file_seek(file, offset, false)));
|
||||
}
|
||||
|
||||
static void js_storage_file_seek_absolute(struct mjs* mjs) {
|
||||
int32_t offset;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_INT32(&offset));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_1_int_args, &offset);
|
||||
File* file = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_file_seek(file, offset, true)));
|
||||
}
|
||||
|
||||
static void js_storage_file_tell(struct mjs* mjs) {
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY); // 0 args
|
||||
File* file = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_number(mjs, storage_file_tell(file)));
|
||||
}
|
||||
|
||||
static void js_storage_file_truncate(struct mjs* mjs) {
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY); // 0 args
|
||||
File* file = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_file_truncate(file)));
|
||||
}
|
||||
|
||||
static void js_storage_file_size(struct mjs* mjs) {
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY); // 0 args
|
||||
File* file = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_number(mjs, storage_file_size(file)));
|
||||
}
|
||||
|
||||
static void js_storage_file_eof(struct mjs* mjs) {
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY); // 0 args
|
||||
File* file = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_file_eof(file)));
|
||||
}
|
||||
|
||||
static void js_storage_file_copy_to(struct mjs* mjs) {
|
||||
File* source = JS_GET_CONTEXT(mjs);
|
||||
static const JsValueDeclaration js_storage_file_write_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeAny),
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
};
|
||||
static const JsValueArguments js_storage_file_write_args =
|
||||
JS_VALUE_ARGS(js_storage_file_write_arg_list);
|
||||
|
||||
mjs_val_t dest_obj;
|
||||
int32_t bytes;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_OBJ(&dest_obj), JS_ARG_INT32(&bytes));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_file_write_args, &dest_obj, &bytes);
|
||||
|
||||
File* source = JS_GET_CONTEXT(mjs);
|
||||
File* destination = JS_GET_INST(mjs, dest_obj);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_file_copy_to_file(source, destination, bytes)));
|
||||
}
|
||||
|
||||
// ---=== top-level file ops ===---
|
||||
// =========================
|
||||
// Top-level file operations
|
||||
// =========================
|
||||
|
||||
// common destructor for file and dir objects
|
||||
static void js_storage_file_destructor(struct mjs* mjs, mjs_val_t obj) {
|
||||
@@ -106,23 +149,33 @@ static void js_storage_file_destructor(struct mjs* mjs, mjs_val_t obj) {
|
||||
}
|
||||
|
||||
static void js_storage_open_file(struct mjs* mjs) {
|
||||
const char* path;
|
||||
FS_AccessMode access_mode;
|
||||
FS_OpenMode open_mode;
|
||||
JS_ENUM_MAP(access_mode, {"r", FSAM_READ}, {"w", FSAM_WRITE}, {"rw", FSAM_READ_WRITE});
|
||||
JS_ENUM_MAP(
|
||||
open_mode,
|
||||
static const JsValueEnumVariant js_storage_fsam_variants[] = {
|
||||
{"r", FSAM_READ},
|
||||
{"w", FSAM_WRITE},
|
||||
{"rw", FSAM_READ_WRITE},
|
||||
};
|
||||
|
||||
static const JsValueEnumVariant js_storage_fsom_variants[] = {
|
||||
{"open_existing", FSOM_OPEN_EXISTING},
|
||||
{"open_always", FSOM_OPEN_ALWAYS},
|
||||
{"open_append", FSOM_OPEN_APPEND},
|
||||
{"create_new", FSOM_CREATE_NEW},
|
||||
{"create_always", FSOM_CREATE_ALWAYS});
|
||||
JS_FETCH_ARGS_OR_RETURN(
|
||||
mjs,
|
||||
JS_EXACTLY,
|
||||
JS_ARG_STR(&path),
|
||||
JS_ARG_ENUM(access_mode, "AccessMode"),
|
||||
JS_ARG_ENUM(open_mode, "OpenMode"));
|
||||
{"create_always", FSOM_CREATE_ALWAYS},
|
||||
};
|
||||
|
||||
static const JsValueDeclaration js_storage_open_file_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeString),
|
||||
JS_VALUE_ENUM(FS_AccessMode, js_storage_fsam_variants),
|
||||
JS_VALUE_ENUM(FS_OpenMode, js_storage_fsom_variants),
|
||||
};
|
||||
static const JsValueArguments js_storage_open_file_args =
|
||||
JS_VALUE_ARGS(js_storage_open_file_arg_list);
|
||||
|
||||
const char* path;
|
||||
FS_AccessMode access_mode;
|
||||
FS_OpenMode open_mode;
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(
|
||||
mjs, &js_storage_open_file_args, &path, &access_mode, &open_mode);
|
||||
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
File* file = storage_file_alloc(storage);
|
||||
@@ -152,16 +205,18 @@ static void js_storage_open_file(struct mjs* mjs) {
|
||||
|
||||
static void js_storage_file_exists(struct mjs* mjs) {
|
||||
const char* path;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&path));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_1_str_args, &path);
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_file_exists(storage, path)));
|
||||
}
|
||||
|
||||
// ---=== dir ops ===---
|
||||
// ====================
|
||||
// Directory operations
|
||||
// ====================
|
||||
|
||||
static void js_storage_read_directory(struct mjs* mjs) {
|
||||
const char* path;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&path));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_1_str_args, &path);
|
||||
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
File* dir = storage_file_alloc(storage);
|
||||
@@ -200,30 +255,32 @@ static void js_storage_read_directory(struct mjs* mjs) {
|
||||
|
||||
static void js_storage_directory_exists(struct mjs* mjs) {
|
||||
const char* path;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&path));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_1_str_args, &path);
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_dir_exists(storage, path)));
|
||||
}
|
||||
|
||||
static void js_storage_make_directory(struct mjs* mjs) {
|
||||
const char* path;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&path));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_1_str_args, &path);
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_simply_mkdir(storage, path)));
|
||||
}
|
||||
|
||||
// ---=== common ops ===---
|
||||
// =================
|
||||
// Common operations
|
||||
// =================
|
||||
|
||||
static void js_storage_file_or_dir_exists(struct mjs* mjs) {
|
||||
const char* path;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&path));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_1_str_args, &path);
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_common_exists(storage, path)));
|
||||
}
|
||||
|
||||
static void js_storage_stat(struct mjs* mjs) {
|
||||
const char* path;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&path));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_1_str_args, &path);
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
FileInfo file_info;
|
||||
uint32_t timestamp;
|
||||
@@ -244,21 +301,21 @@ static void js_storage_stat(struct mjs* mjs) {
|
||||
|
||||
static void js_storage_remove(struct mjs* mjs) {
|
||||
const char* path;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&path));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_1_str_args, &path);
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_simply_remove(storage, path)));
|
||||
}
|
||||
|
||||
static void js_storage_rmrf(struct mjs* mjs) {
|
||||
const char* path;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&path));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_1_str_args, &path);
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_simply_remove_recursive(storage, path)));
|
||||
}
|
||||
|
||||
static void js_storage_rename(struct mjs* mjs) {
|
||||
const char *old, *new;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&old), JS_ARG_STR(&new));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_2_str_args, &old, &new);
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
FS_Error status = storage_common_rename(storage, old, new);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, status == FSE_OK));
|
||||
@@ -266,7 +323,7 @@ static void js_storage_rename(struct mjs* mjs) {
|
||||
|
||||
static void js_storage_copy(struct mjs* mjs) {
|
||||
const char *source, *dest;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&source), JS_ARG_STR(&dest));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_2_str_args, &source, &dest);
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
FS_Error status = storage_common_copy(storage, source, dest);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, status == FSE_OK || status == FSE_EXIST));
|
||||
@@ -274,7 +331,7 @@ static void js_storage_copy(struct mjs* mjs) {
|
||||
|
||||
static void js_storage_fs_info(struct mjs* mjs) {
|
||||
const char* fs;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&fs));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_1_str_args, &fs);
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
uint64_t total_space, free_space;
|
||||
if(storage_common_fs_info(storage, fs, &total_space, &free_space) != FSE_OK) {
|
||||
@@ -290,15 +347,19 @@ static void js_storage_fs_info(struct mjs* mjs) {
|
||||
}
|
||||
|
||||
static void js_storage_next_available_filename(struct mjs* mjs) {
|
||||
static const JsValueDeclaration js_storage_naf_arg_list[] = {
|
||||
JS_VALUE_SIMPLE(JsValueTypeString),
|
||||
JS_VALUE_SIMPLE(JsValueTypeString),
|
||||
JS_VALUE_SIMPLE(JsValueTypeString),
|
||||
JS_VALUE_SIMPLE(JsValueTypeInt32),
|
||||
};
|
||||
static const JsValueArguments js_storage_naf_args = JS_VALUE_ARGS(js_storage_naf_arg_list);
|
||||
|
||||
const char *dir_path, *file_name, *file_ext;
|
||||
int32_t max_len;
|
||||
JS_FETCH_ARGS_OR_RETURN(
|
||||
mjs,
|
||||
JS_EXACTLY,
|
||||
JS_ARG_STR(&dir_path),
|
||||
JS_ARG_STR(&file_name),
|
||||
JS_ARG_STR(&file_ext),
|
||||
JS_ARG_INT32(&max_len));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(
|
||||
mjs, &js_storage_naf_args, &dir_path, &file_name, &file_ext, &max_len);
|
||||
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
FuriString* next_name = furi_string_alloc();
|
||||
storage_get_next_filename(storage, dir_path, file_name, file_ext, next_name, max_len);
|
||||
@@ -306,23 +367,27 @@ static void js_storage_next_available_filename(struct mjs* mjs) {
|
||||
furi_string_free(next_name);
|
||||
}
|
||||
|
||||
// ---=== path ops ===---
|
||||
// ===============
|
||||
// Path operations
|
||||
// ===============
|
||||
|
||||
static void js_storage_are_paths_equal(struct mjs* mjs) {
|
||||
const char *path1, *path2;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&path1), JS_ARG_STR(&path2));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_2_str_args, &path1, &path2);
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_common_equivalent_path(storage, path1, path2)));
|
||||
}
|
||||
|
||||
static void js_storage_is_subpath_of(struct mjs* mjs) {
|
||||
const char *parent, *child;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&parent), JS_ARG_STR(&child));
|
||||
JS_VALUE_PARSE_ARGS_OR_RETURN(mjs, &js_storage_2_str_args, &parent, &child);
|
||||
Storage* storage = JS_GET_CONTEXT(mjs);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, storage_common_is_subdir(storage, parent, child)));
|
||||
}
|
||||
|
||||
// ---=== module ctor & dtor ===---
|
||||
// ==================
|
||||
// Module ctor & dtor
|
||||
// ==================
|
||||
|
||||
static void* js_storage_create(struct mjs* mjs, mjs_val_t* object, JsModules* modules) {
|
||||
UNUSED(modules);
|
||||
@@ -363,7 +428,9 @@ static void js_storage_destroy(void* data) {
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
// ---=== boilerplate ===---
|
||||
// ===========
|
||||
// Boilerplate
|
||||
// ===========
|
||||
|
||||
static const JsModuleDescriptor js_storage_desc = {
|
||||
"storage",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "js_plugin_api.h"
|
||||
#include "../js_modules.h"
|
||||
|
||||
/*
|
||||
* A list of app's private functions and objects to expose for plugins.
|
||||
* It is used to generate a table of symbols for import resolver to use.
|
||||
@@ -8,4 +9,16 @@ static constexpr auto app_api_table = sort(create_array_t<sym_entry>(
|
||||
API_METHOD(js_delay_with_flags, bool, (struct mjs*, uint32_t)),
|
||||
API_METHOD(js_flags_set, void, (struct mjs*, uint32_t)),
|
||||
API_METHOD(js_flags_wait, uint32_t, (struct mjs*, uint32_t, uint32_t)),
|
||||
API_METHOD(js_module_get, void*, (JsModules*, const char*))));
|
||||
API_METHOD(js_module_get, void*, (JsModules*, const char*)),
|
||||
API_METHOD(js_value_buffer_size, size_t, (const JsValueParseDeclaration declaration)),
|
||||
API_METHOD(
|
||||
js_value_parse,
|
||||
JsValueParseStatus,
|
||||
(struct mjs * mjs,
|
||||
const JsValueParseDeclaration declaration,
|
||||
JsValueParseFlag flags,
|
||||
mjs_val_t* buffer,
|
||||
size_t buf_size,
|
||||
mjs_val_t* source,
|
||||
size_t n_c_vals,
|
||||
...))));
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <mjs_core_public.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void JsModules;
|
||||
|
||||
bool js_delay_with_flags(struct mjs* mjs, uint32_t time);
|
||||
|
||||
void js_flags_set(struct mjs* mjs, uint32_t flags);
|
||||
|
||||
uint32_t js_flags_wait(struct mjs* mjs, uint32_t flags, uint32_t timeout);
|
||||
|
||||
void* js_module_get(JsModules* modules, const char* name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user