mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-06-17 20:19:43 -07:00
Merge remote-tracking branch 'ul/dev' into mntm-dev
This commit is contained in:
@@ -2404,6 +2404,8 @@ FE98F38F3EE2
|
||||
555D8BBC2D3E
|
||||
78DF1176C8FD
|
||||
ADC169F922CB
|
||||
# iq aparts hotel
|
||||
505209266A1F
|
||||
# +------------------------------------------------------------------------------------------------------------------------+
|
||||
# | https://github.com/Flipper-XFW/Xtreme-Firmware/blob/dev/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc |
|
||||
# +------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
@@ -674,14 +674,14 @@ void cli_commands_init(Cli* cli) {
|
||||
cli_add_command(cli, "!", CliCommandFlagParallelSafe, cli_command_info, (void*)true);
|
||||
cli_add_command(cli, "info", CliCommandFlagParallelSafe, cli_command_info, NULL);
|
||||
cli_add_command(cli, "device_info", CliCommandFlagParallelSafe, cli_command_info, (void*)true);
|
||||
cli_add_command(cli, "source", CliCommandFlagParallelSafe, cli_command_src, NULL);
|
||||
cli_add_command(cli, "src", CliCommandFlagParallelSafe, cli_command_src, NULL);
|
||||
cli_add_command(
|
||||
cli,
|
||||
"neofetch",
|
||||
CliCommandFlagParallelSafe | CliCommandFlagHidden,
|
||||
cli_command_neofetch,
|
||||
NULL);
|
||||
cli_add_command(cli, "src", CliCommandFlagParallelSafe, cli_command_src, NULL);
|
||||
cli_add_command(cli, "source", CliCommandFlagParallelSafe, cli_command_src, NULL);
|
||||
|
||||
cli_add_command(cli, "?", CliCommandFlagParallelSafe, cli_command_help, NULL);
|
||||
cli_add_command(cli, "help", CliCommandFlagParallelSafe, cli_command_help, NULL);
|
||||
|
||||
@@ -87,6 +87,14 @@ App(
|
||||
sources=["modules/js_gui/text_input.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_gui__byte_input",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_view_byte_input_ep",
|
||||
requires=["js_app", "js_gui", "js_event_loop"],
|
||||
sources=["modules/js_gui/byte_input.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_gui__text_box",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
@@ -127,14 +135,6 @@ App(
|
||||
sources=["modules/js_serial.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_usbdisk",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_usbdisk_ep",
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_usbdisk/*.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_gpio",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
@@ -143,14 +143,6 @@ App(
|
||||
sources=["modules/js_gpio.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_blebeacon",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_blebeacon_ep",
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_blebeacon.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_math",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
@@ -159,22 +151,6 @@ App(
|
||||
sources=["modules/js_math.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_keyboard",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_keyboard_ep",
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_keyboard.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_subghz",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_subghz_ep",
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_subghz/*.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_storage",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
@@ -198,3 +174,27 @@ App(
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_vgm/*.c", "modules/js_vgm/ICM42688P/*.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_subghz",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_subghz_ep",
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_subghz/*.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_blebeacon",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_blebeacon_ep",
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_blebeacon.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_usbdisk",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_usbdisk_ep",
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_usbdisk/*.c"],
|
||||
)
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
let eventLoop = require("event_loop");
|
||||
let gpio = require("gpio");
|
||||
|
||||
// initialize pins
|
||||
gpio.init("PC3", "outputPushPull", "up"); // pin, mode, pull
|
||||
print("PC3 is initialized as outputPushPull with pull-up");
|
||||
let led = gpio.get("pc3"); // same as `gpio.get(7)`
|
||||
let pot = gpio.get("pc0"); // same as `gpio.get(16)`
|
||||
let button = gpio.get("pc1"); // same as `gpio.get(15)`
|
||||
led.init({ direction: "out", outMode: "push_pull" });
|
||||
pot.init({ direction: "in", inMode: "analog" });
|
||||
button.init({ direction: "in", pull: "up", inMode: "interrupt", edge: "falling" });
|
||||
|
||||
gpio.init("PC1", "input", "down"); // pin, mode, pull
|
||||
print("PC1 is initialized as input with pull-down");
|
||||
// blink led
|
||||
print("Commencing blinking (PC3)");
|
||||
eventLoop.subscribe(eventLoop.timer("periodic", 1000), function (_, _item, led, state) {
|
||||
led.write(state);
|
||||
return [led, !state];
|
||||
}, led, true);
|
||||
|
||||
// let led on PC3 blink
|
||||
gpio.write("PC3", true); // high
|
||||
delay(1000);
|
||||
gpio.write("PC3", false); // low
|
||||
delay(1000);
|
||||
gpio.write("PC3", true); // high
|
||||
delay(1000);
|
||||
gpio.write("PC3", false); // low
|
||||
|
||||
// read value from PC1 and write it to PC3
|
||||
while (true) {
|
||||
let value = gpio.read("PC1");
|
||||
gpio.write("PC3", value);
|
||||
|
||||
value ? print("PC1 is high") : print("PC1 is low");
|
||||
|
||||
delay(100);
|
||||
}
|
||||
// read potentiometer when button is pressed
|
||||
print("Press the button (PC1)");
|
||||
eventLoop.subscribe(button.interrupt(), function (_, _item, pot) {
|
||||
print("PC0 is at", pot.read_analog(), "mV");
|
||||
}, pot);
|
||||
|
||||
// the program will just exit unless this is here
|
||||
eventLoop.run();
|
||||
|
||||
// possible pins https://docs.flipper.net/gpio-and-modules#miFsS
|
||||
// "PA7" aka 2
|
||||
@@ -43,20 +41,17 @@ while (true) {
|
||||
// "PB14" aka 17
|
||||
|
||||
// possible modes
|
||||
// "input"
|
||||
// "outputPushPull"
|
||||
// "outputOpenDrain"
|
||||
// "altFunctionPushPull"
|
||||
// "altFunctionOpenDrain"
|
||||
// "analog"
|
||||
// "interruptRise"
|
||||
// "interruptFall"
|
||||
// "interruptRiseFall"
|
||||
// "eventRise"
|
||||
// "eventFall"
|
||||
// "eventRiseFall"
|
||||
|
||||
// possible pull
|
||||
// "no"
|
||||
// "up"
|
||||
// "down"
|
||||
// { direction: "out", outMode: "push_pull" }
|
||||
// { direction: "out", outMode: "open_drain" }
|
||||
// { direction: "out", outMode: "push_pull", altFn: true }
|
||||
// { direction: "out", outMode: "open_drain", altFn: true }
|
||||
// { direction: "in", inMode: "analog" }
|
||||
// { direction: "in", inMode: "plain_digital" }
|
||||
// { direction: "in", inMode: "interrupt", edge: "rising" }
|
||||
// { direction: "in", inMode: "interrupt", edge: "falling" }
|
||||
// { direction: "in", inMode: "interrupt", edge: "both" }
|
||||
// { direction: "in", inMode: "event", edge: "rising" }
|
||||
// { direction: "in", inMode: "event", edge: "falling" }
|
||||
// { direction: "in", inMode: "event", edge: "both" }
|
||||
// all variants support an optional `pull` field which can either be undefined,
|
||||
// "up" or "down"
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
let eventLoop = require("event_loop");
|
||||
let gpio = require("gpio");
|
||||
|
||||
// initialize pins
|
||||
let led = gpio.get("pc3"); // same as `gpio.get(7)`
|
||||
let pot = gpio.get("pc0"); // same as `gpio.get(16)`
|
||||
let button = gpio.get("pc1"); // same as `gpio.get(15)`
|
||||
led.init({ direction: "out", outMode: "push_pull" });
|
||||
pot.init({ direction: "in", inMode: "analog" });
|
||||
button.init({ direction: "in", pull: "up", inMode: "interrupt", edge: "falling" });
|
||||
|
||||
// blink led
|
||||
print("Commencing blinking (PC3)");
|
||||
eventLoop.subscribe(eventLoop.timer("periodic", 1000), function (_, _item, led, state) {
|
||||
led.write(state);
|
||||
return [led, !state];
|
||||
}, led, true);
|
||||
|
||||
// read potentiometer when button is pressed
|
||||
print("Press the button (PC1)");
|
||||
eventLoop.subscribe(button.interrupt(), function (_, _item, pot) {
|
||||
print("PC0 is at", pot.read_analog(), "mV");
|
||||
}, pot);
|
||||
|
||||
// the program will just exit unless this is here
|
||||
eventLoop.run();
|
||||
|
||||
// possible pins https://docs.flipper.net/gpio-and-modules#miFsS
|
||||
// "PA7" aka 2
|
||||
// "PA6" aka 3
|
||||
// "PA4" aka 4
|
||||
// "PB3" aka 5
|
||||
// "PB2" aka 6
|
||||
// "PC3" aka 7
|
||||
// "PA14" aka 10
|
||||
// "PA13" aka 12
|
||||
// "PB6" aka 13
|
||||
// "PB7" aka 14
|
||||
// "PC1" aka 15
|
||||
// "PC0" aka 16
|
||||
// "PB14" aka 17
|
||||
|
||||
// possible modes
|
||||
// { direction: "out", outMode: "push_pull" }
|
||||
// { direction: "out", outMode: "open_drain" }
|
||||
// { direction: "out", outMode: "push_pull", altFn: true }
|
||||
// { direction: "out", outMode: "open_drain", altFn: true }
|
||||
// { direction: "in", inMode: "analog" }
|
||||
// { direction: "in", inMode: "plain_digital" }
|
||||
// { direction: "in", inMode: "interrupt", edge: "rising" }
|
||||
// { direction: "in", inMode: "interrupt", edge: "falling" }
|
||||
// { direction: "in", inMode: "interrupt", edge: "both" }
|
||||
// { direction: "in", inMode: "event", edge: "rising" }
|
||||
// { direction: "in", inMode: "event", edge: "falling" }
|
||||
// { direction: "in", inMode: "event", edge: "both" }
|
||||
// all variants support an optional `pull` field which can either be undefined,
|
||||
// "up" or "down"
|
||||
@@ -221,7 +221,7 @@ static void js_badusb_is_connected(struct mjs* mjs) {
|
||||
|
||||
uint16_t get_keycode_by_name(JsBadusbInst* badusb, const char* key_name, size_t name_len) {
|
||||
if(name_len == 1) { // Single char
|
||||
return ASCII_TO_KEY(badusb->layout, key_name[0]);
|
||||
return (ASCII_TO_KEY(badusb->layout, key_name[0]));
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < COUNT_OF(key_codes); i++) {
|
||||
|
||||
@@ -193,7 +193,8 @@ static void js_blebeacon_keep_alive(struct mjs* mjs) {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
||||
static void* js_blebeacon_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
static void* js_blebeacon_create(struct mjs* mjs, mjs_val_t* object, JsModules* modules) {
|
||||
UNUSED(modules);
|
||||
JsBlebeaconInst* blebeacon = malloc(sizeof(JsBlebeaconInst));
|
||||
mjs_val_t blebeacon_obj = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, blebeacon_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, blebeacon));
|
||||
@@ -231,6 +232,7 @@ static const JsModuleDescriptor js_blebeacon_desc = {
|
||||
"blebeacon",
|
||||
js_blebeacon_create,
|
||||
js_blebeacon_destroy,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "../../js_modules.h" // IWYU pragma: keep
|
||||
#include "js_gui.h"
|
||||
#include "../js_event_loop/js_event_loop.h"
|
||||
#include <gui/modules/byte_input.h>
|
||||
|
||||
#define DEFAULT_BUF_SZ 4
|
||||
|
||||
typedef struct {
|
||||
uint8_t* buffer;
|
||||
size_t buffer_size;
|
||||
FuriString* header;
|
||||
FuriSemaphore* input_semaphore;
|
||||
JsEventLoopContract contract;
|
||||
} JsByteKbContext;
|
||||
|
||||
static mjs_val_t
|
||||
input_transformer(struct mjs* mjs, FuriSemaphore* semaphore, JsByteKbContext* context) {
|
||||
furi_check(furi_semaphore_acquire(semaphore, 0) == FuriStatusOk);
|
||||
return mjs_mk_array_buf(mjs, (char*)context->buffer, context->buffer_size);
|
||||
}
|
||||
|
||||
static void input_callback(JsByteKbContext* context) {
|
||||
furi_semaphore_release(context->input_semaphore);
|
||||
}
|
||||
|
||||
static bool header_assign(
|
||||
struct mjs* mjs,
|
||||
ByteInput* input,
|
||||
JsViewPropValue value,
|
||||
JsByteKbContext* context) {
|
||||
UNUSED(mjs);
|
||||
furi_string_set(context->header, value.string);
|
||||
byte_input_set_header_text(input, furi_string_get_cstr(context->header));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
len_assign(struct mjs* mjs, ByteInput* input, JsViewPropValue value, JsByteKbContext* context) {
|
||||
UNUSED(mjs);
|
||||
UNUSED(input);
|
||||
context->buffer_size = (size_t)(value.number);
|
||||
context->buffer = realloc(context->buffer, context->buffer_size); //-V701
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool default_data_assign(
|
||||
struct mjs* mjs,
|
||||
ByteInput* input,
|
||||
JsViewPropValue value,
|
||||
JsByteKbContext* context) {
|
||||
UNUSED(mjs);
|
||||
|
||||
if(mjs_is_data_view(value.array)) {
|
||||
value.array = mjs_dataview_get_buf(mjs, value.array);
|
||||
}
|
||||
size_t default_data_len = 0;
|
||||
char* default_data = mjs_array_buf_get_ptr(mjs, value.array, &default_data_len);
|
||||
memcpy(
|
||||
context->buffer,
|
||||
(uint8_t*)default_data,
|
||||
MIN((size_t)context->buffer_size, default_data_len));
|
||||
|
||||
byte_input_set_result_callback(
|
||||
input,
|
||||
(ByteInputCallback)input_callback,
|
||||
NULL,
|
||||
context,
|
||||
context->buffer,
|
||||
context->buffer_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JsByteKbContext* ctx_make(struct mjs* mjs, ByteInput* input, mjs_val_t view_obj) {
|
||||
UNUSED(input);
|
||||
JsByteKbContext* context = malloc(sizeof(JsByteKbContext));
|
||||
*context = (JsByteKbContext){
|
||||
.buffer_size = DEFAULT_BUF_SZ,
|
||||
.buffer = malloc(DEFAULT_BUF_SZ),
|
||||
.header = furi_string_alloc(),
|
||||
.input_semaphore = furi_semaphore_alloc(1, 0),
|
||||
};
|
||||
context->contract = (JsEventLoopContract){
|
||||
.magic = JsForeignMagic_JsEventLoopContract,
|
||||
.object_type = JsEventLoopObjectTypeSemaphore,
|
||||
.object = context->input_semaphore,
|
||||
.non_timer =
|
||||
{
|
||||
.event = FuriEventLoopEventIn,
|
||||
.transformer = (JsEventLoopTransformer)input_transformer,
|
||||
.transformer_context = context,
|
||||
},
|
||||
};
|
||||
UNUSED(mjs);
|
||||
UNUSED(view_obj);
|
||||
mjs_set(mjs, view_obj, "input", ~0, mjs_mk_foreign(mjs, &context->contract));
|
||||
return context;
|
||||
}
|
||||
|
||||
static void ctx_destroy(ByteInput* input, JsByteKbContext* context, FuriEventLoop* loop) {
|
||||
UNUSED(input);
|
||||
furi_event_loop_maybe_unsubscribe(loop, context->input_semaphore);
|
||||
furi_semaphore_free(context->input_semaphore);
|
||||
furi_string_free(context->header);
|
||||
free(context->buffer);
|
||||
free(context);
|
||||
}
|
||||
|
||||
static const JsViewDescriptor view_descriptor = {
|
||||
.alloc = (JsViewAlloc)byte_input_alloc,
|
||||
.free = (JsViewFree)byte_input_free,
|
||||
.get_view = (JsViewGetView)byte_input_get_view,
|
||||
.custom_make = (JsViewCustomMake)ctx_make,
|
||||
.custom_destroy = (JsViewCustomDestroy)ctx_destroy,
|
||||
.prop_cnt = 3,
|
||||
.props = {
|
||||
(JsViewPropDescriptor){
|
||||
.name = "header",
|
||||
.type = JsViewPropTypeString,
|
||||
.assign = (JsViewPropAssign)header_assign},
|
||||
(JsViewPropDescriptor){
|
||||
.name = "length",
|
||||
.type = JsViewPropTypeNumber,
|
||||
.assign = (JsViewPropAssign)len_assign},
|
||||
(JsViewPropDescriptor){
|
||||
.name = "defaultData",
|
||||
.type = JsViewPropTypeTypedArr,
|
||||
.assign = (JsViewPropAssign)default_data_assign},
|
||||
}};
|
||||
|
||||
JS_GUI_VIEW_DEF(byte_input, &view_descriptor);
|
||||
@@ -215,6 +215,20 @@ static bool
|
||||
}
|
||||
c_value = (JsViewPropValue){.array = value};
|
||||
} break;
|
||||
case JsViewPropTypeTypedArr: {
|
||||
if(!mjs_is_typed_array(value)) {
|
||||
expected_type = "typed_array";
|
||||
break;
|
||||
}
|
||||
c_value = (JsViewPropValue){.array = value};
|
||||
} break;
|
||||
case JsViewPropTypeBool: {
|
||||
if(!mjs_is_boolean(value)) {
|
||||
expected_type = "bool";
|
||||
break;
|
||||
}
|
||||
c_value = (JsViewPropValue){.boolean = mjs_get_bool(mjs, value)};
|
||||
} break;
|
||||
}
|
||||
|
||||
if(expected_type) {
|
||||
|
||||
@@ -9,12 +9,15 @@ typedef enum {
|
||||
JsViewPropTypeString,
|
||||
JsViewPropTypeNumber,
|
||||
JsViewPropTypeArr,
|
||||
JsViewPropTypeTypedArr,
|
||||
JsViewPropTypeBool,
|
||||
} JsViewPropType;
|
||||
|
||||
typedef union {
|
||||
const char* string;
|
||||
int32_t number;
|
||||
mjs_val_t array;
|
||||
bool boolean;
|
||||
} JsViewPropValue;
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,15 +48,40 @@ static bool max_len_assign(
|
||||
JsViewPropValue value,
|
||||
JsKbdContext* context) {
|
||||
UNUSED(mjs);
|
||||
UNUSED(input);
|
||||
context->buffer_size = (size_t)(value.number + 1);
|
||||
context->buffer = realloc(context->buffer, context->buffer_size); //-V701
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool default_text_assign(
|
||||
struct mjs* mjs,
|
||||
TextInput* input,
|
||||
JsViewPropValue value,
|
||||
JsKbdContext* context) {
|
||||
UNUSED(mjs);
|
||||
UNUSED(input);
|
||||
|
||||
if(value.string) {
|
||||
strlcpy(context->buffer, value.string, context->buffer_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool default_text_clear_assign(
|
||||
struct mjs* mjs,
|
||||
TextInput* input,
|
||||
JsViewPropValue value,
|
||||
JsKbdContext* context) {
|
||||
UNUSED(mjs);
|
||||
|
||||
text_input_set_result_callback(
|
||||
input,
|
||||
(TextInputCallback)input_callback,
|
||||
context,
|
||||
context->buffer,
|
||||
context->buffer_size,
|
||||
true);
|
||||
value.boolean);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -101,7 +126,7 @@ static const JsViewDescriptor view_descriptor = {
|
||||
.get_view = (JsViewGetView)text_input_get_view,
|
||||
.custom_make = (JsViewCustomMake)ctx_make,
|
||||
.custom_destroy = (JsViewCustomDestroy)ctx_destroy,
|
||||
.prop_cnt = 3,
|
||||
.prop_cnt = 5,
|
||||
.props = {
|
||||
(JsViewPropDescriptor){
|
||||
.name = "header",
|
||||
@@ -115,6 +140,14 @@ static const JsViewDescriptor view_descriptor = {
|
||||
.name = "maxLength",
|
||||
.type = JsViewPropTypeNumber,
|
||||
.assign = (JsViewPropAssign)max_len_assign},
|
||||
(JsViewPropDescriptor){
|
||||
.name = "defaultText",
|
||||
.type = JsViewPropTypeString,
|
||||
.assign = (JsViewPropAssign)default_text_assign},
|
||||
(JsViewPropDescriptor){
|
||||
.name = "defaultTextClear",
|
||||
.type = JsViewPropTypeBool,
|
||||
.assign = (JsViewPropAssign)default_text_clear_assign},
|
||||
}};
|
||||
|
||||
JS_GUI_VIEW_DEF(text_input, &view_descriptor);
|
||||
|
||||
@@ -1,206 +0,0 @@
|
||||
#include "../js_modules.h"
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/modules/byte_input.h>
|
||||
#include <gui/view_holder.h>
|
||||
#include <toolbox/api_lock.h>
|
||||
|
||||
#define membersof(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
typedef struct {
|
||||
TextInput* text_input;
|
||||
ByteInput* byte_input;
|
||||
ViewHolder* view_holder;
|
||||
FuriApiLock lock;
|
||||
char* header;
|
||||
bool accepted;
|
||||
} JsKeyboardInst;
|
||||
|
||||
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 JsKeyboardInst* get_this_ctx(struct mjs* mjs) {
|
||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||
JsKeyboardInst* keyboard = mjs_get_ptr(mjs, obj_inst);
|
||||
furi_assert(keyboard);
|
||||
return keyboard;
|
||||
}
|
||||
|
||||
static void keyboard_callback(void* context) {
|
||||
JsKeyboardInst* keyboard = (JsKeyboardInst*)context;
|
||||
keyboard->accepted = true;
|
||||
api_lock_unlock(keyboard->lock);
|
||||
}
|
||||
|
||||
static void keyboard_exit(void* context) {
|
||||
JsKeyboardInst* keyboard = (JsKeyboardInst*)context;
|
||||
keyboard->accepted = false;
|
||||
api_lock_unlock(keyboard->lock);
|
||||
}
|
||||
|
||||
static void js_keyboard_set_header(struct mjs* mjs) {
|
||||
JsKeyboardInst* keyboard = get_this_ctx(mjs);
|
||||
|
||||
mjs_val_t header_arg = mjs_arg(mjs, 0);
|
||||
const char* header = mjs_get_string(mjs, &header_arg, NULL);
|
||||
if(!header) {
|
||||
ret_bad_args(mjs, "Header must be a string");
|
||||
return;
|
||||
}
|
||||
|
||||
if(keyboard->header) {
|
||||
free(keyboard->header);
|
||||
}
|
||||
keyboard->header = strdup(header);
|
||||
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
||||
static void js_keyboard_text(struct mjs* mjs) {
|
||||
JsKeyboardInst* keyboard = get_this_ctx(mjs);
|
||||
|
||||
mjs_val_t input_length_arg = mjs_arg(mjs, 0);
|
||||
if(!mjs_is_number(input_length_arg)) {
|
||||
ret_bad_args(mjs, "Input length must be a number");
|
||||
return;
|
||||
}
|
||||
int32_t input_length = mjs_get_int32(mjs, input_length_arg);
|
||||
char* buffer = malloc(input_length);
|
||||
|
||||
mjs_val_t default_text_arg = mjs_arg(mjs, 1);
|
||||
const char* default_text = mjs_get_string(mjs, &default_text_arg, NULL);
|
||||
bool clear_default = false;
|
||||
if(default_text) {
|
||||
strlcpy(buffer, default_text, input_length);
|
||||
mjs_val_t bool_obj = mjs_arg(mjs, 2);
|
||||
clear_default = mjs_get_bool(mjs, bool_obj);
|
||||
}
|
||||
|
||||
if(keyboard->header) {
|
||||
text_input_set_header_text(keyboard->text_input, keyboard->header);
|
||||
}
|
||||
text_input_set_result_callback(
|
||||
keyboard->text_input, keyboard_callback, keyboard, buffer, input_length, clear_default);
|
||||
text_input_add_illegal_symbols(keyboard->text_input);
|
||||
text_input_set_minimum_length(keyboard->text_input, 0);
|
||||
|
||||
keyboard->lock = api_lock_alloc_locked();
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
keyboard->view_holder = view_holder_alloc();
|
||||
view_holder_attach_to_gui(keyboard->view_holder, gui);
|
||||
view_holder_set_back_callback(keyboard->view_holder, keyboard_exit, keyboard);
|
||||
|
||||
view_holder_set_view(keyboard->view_holder, text_input_get_view(keyboard->text_input));
|
||||
api_lock_wait_unlock(keyboard->lock);
|
||||
|
||||
view_holder_set_view(keyboard->view_holder, NULL);
|
||||
view_holder_free(keyboard->view_holder);
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
api_lock_free(keyboard->lock);
|
||||
|
||||
text_input_reset(keyboard->text_input);
|
||||
if(keyboard->header) {
|
||||
free(keyboard->header);
|
||||
keyboard->header = NULL;
|
||||
}
|
||||
if(keyboard->accepted) {
|
||||
mjs_return(mjs, mjs_mk_string(mjs, buffer, ~0, true));
|
||||
} else {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void js_keyboard_byte(struct mjs* mjs) {
|
||||
JsKeyboardInst* keyboard = get_this_ctx(mjs);
|
||||
|
||||
mjs_val_t input_length_arg = mjs_arg(mjs, 0);
|
||||
if(!mjs_is_number(input_length_arg)) {
|
||||
ret_bad_args(mjs, "Input length must be a number");
|
||||
return;
|
||||
}
|
||||
int32_t input_length = mjs_get_int32(mjs, input_length_arg);
|
||||
uint8_t* buffer = malloc(input_length);
|
||||
|
||||
mjs_val_t default_data_arg = mjs_arg(mjs, 1);
|
||||
if(mjs_is_typed_array(default_data_arg)) {
|
||||
if(mjs_is_data_view(default_data_arg)) {
|
||||
default_data_arg = mjs_dataview_get_buf(mjs, default_data_arg);
|
||||
}
|
||||
size_t default_data_len = 0;
|
||||
char* default_data = mjs_array_buf_get_ptr(mjs, default_data_arg, &default_data_len);
|
||||
memcpy(buffer, (uint8_t*)default_data, MIN((size_t)input_length, default_data_len));
|
||||
}
|
||||
|
||||
if(keyboard->header) {
|
||||
byte_input_set_header_text(keyboard->byte_input, keyboard->header);
|
||||
}
|
||||
byte_input_set_result_callback(
|
||||
keyboard->byte_input, keyboard_callback, NULL, keyboard, buffer, input_length);
|
||||
|
||||
keyboard->lock = api_lock_alloc_locked();
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
keyboard->view_holder = view_holder_alloc();
|
||||
view_holder_attach_to_gui(keyboard->view_holder, gui);
|
||||
view_holder_set_back_callback(keyboard->view_holder, keyboard_exit, keyboard);
|
||||
|
||||
view_holder_set_view(keyboard->view_holder, byte_input_get_view(keyboard->byte_input));
|
||||
api_lock_wait_unlock(keyboard->lock);
|
||||
|
||||
view_holder_set_view(keyboard->view_holder, NULL);
|
||||
view_holder_free(keyboard->view_holder);
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
api_lock_free(keyboard->lock);
|
||||
|
||||
if(keyboard->header) {
|
||||
free(keyboard->header);
|
||||
keyboard->header = NULL;
|
||||
}
|
||||
byte_input_set_result_callback(keyboard->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(keyboard->byte_input, "");
|
||||
if(keyboard->accepted) {
|
||||
mjs_return(mjs, mjs_mk_array_buf(mjs, (char*)buffer, input_length));
|
||||
} else {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
JsKeyboardInst* keyboard = malloc(sizeof(JsKeyboardInst));
|
||||
mjs_val_t keyboard_obj = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, keyboard_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, keyboard));
|
||||
mjs_set(mjs, keyboard_obj, "setHeader", ~0, MJS_MK_FN(js_keyboard_set_header));
|
||||
mjs_set(mjs, keyboard_obj, "text", ~0, MJS_MK_FN(js_keyboard_text));
|
||||
mjs_set(mjs, keyboard_obj, "byte", ~0, MJS_MK_FN(js_keyboard_byte));
|
||||
keyboard->byte_input = byte_input_alloc();
|
||||
keyboard->text_input = text_input_alloc();
|
||||
*object = keyboard_obj;
|
||||
return keyboard;
|
||||
}
|
||||
|
||||
static void js_keyboard_destroy(void* inst) {
|
||||
JsKeyboardInst* keyboard = inst;
|
||||
byte_input_free(keyboard->byte_input);
|
||||
text_input_free(keyboard->text_input);
|
||||
free(keyboard);
|
||||
}
|
||||
|
||||
static const JsModuleDescriptor js_keyboard_desc = {
|
||||
"keyboard",
|
||||
js_keyboard_create,
|
||||
js_keyboard_destroy,
|
||||
};
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = PLUGIN_APP_ID,
|
||||
.ep_api_version = PLUGIN_API_VERSION,
|
||||
.entry_point = &js_keyboard_desc,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* js_keyboard_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
}
|
||||
@@ -484,7 +484,8 @@ static void js_subghz_end(struct mjs* mjs) {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
||||
static void* js_subghz_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
static void* js_subghz_create(struct mjs* mjs, mjs_val_t* object, JsModules* modules) {
|
||||
UNUSED(modules);
|
||||
JsSubghzInst* js_subghz = malloc(sizeof(JsSubghzInst));
|
||||
mjs_val_t subghz_obj = mjs_mk_object(mjs);
|
||||
|
||||
@@ -524,6 +525,7 @@ static const JsModuleDescriptor js_subghz_desc = {
|
||||
"subghz",
|
||||
js_subghz_create,
|
||||
js_subghz_destroy,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
|
||||
@@ -237,7 +237,8 @@ static void js_usbdisk_stop(struct mjs* mjs) {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
||||
static void* js_usbdisk_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
static void* js_usbdisk_create(struct mjs* mjs, mjs_val_t* object, JsModules* modules) {
|
||||
UNUSED(modules);
|
||||
JsUsbdiskInst* usbdisk = malloc(sizeof(JsUsbdiskInst));
|
||||
mjs_val_t usbdisk_obj = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, usbdisk_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, usbdisk));
|
||||
@@ -259,6 +260,7 @@ static const JsModuleDescriptor js_usbdisk_desc = {
|
||||
"usbdisk",
|
||||
js_usbdisk_create,
|
||||
js_usbdisk_destroy,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
|
||||
@@ -119,7 +119,8 @@ static void js_vgm_delta_yaw(struct mjs* mjs) {
|
||||
mjs_return(mjs, mjs_mk_number(mjs, 0));
|
||||
}
|
||||
|
||||
static void* js_vgm_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
static void* js_vgm_create(struct mjs* mjs, mjs_val_t* object, JsModules* modules) {
|
||||
UNUSED(modules);
|
||||
JsVgmInst* vgm = malloc(sizeof(JsVgmInst));
|
||||
vgm->imu = imu_alloc();
|
||||
vgm->present = imu_present(vgm->imu);
|
||||
@@ -146,6 +147,7 @@ static const JsModuleDescriptor js_vgm_desc = {
|
||||
name: "vgm",
|
||||
create: js_vgm_create,
|
||||
destroy: js_vgm_destroy,
|
||||
api_interface: NULL,
|
||||
};
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
|
||||
@@ -876,7 +876,8 @@ static void widget_draw_callback(Canvas* canvas, void* model) {
|
||||
}
|
||||
}
|
||||
|
||||
static void* js_widget_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
static void* js_widget_create(struct mjs* mjs, mjs_val_t* object, JsModules* modules) {
|
||||
UNUSED(modules);
|
||||
JsWidgetInst* widget = malloc(sizeof(JsWidgetInst));
|
||||
|
||||
mjs_val_t widget_obj = mjs_mk_object(mjs);
|
||||
@@ -975,6 +976,7 @@ static const JsModuleDescriptor js_widget_desc = {
|
||||
"widget",
|
||||
js_widget_create,
|
||||
js_widget_destroy,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const FlipperAppPluginDescriptor widget_plugin_descriptor = {
|
||||
|
||||
+12
-1
@@ -34,7 +34,7 @@ export type KeyCode = MainKey | ModifierKey | number;
|
||||
* @brief Initializes the module
|
||||
* @param settings USB device settings. Omit to select default parameters
|
||||
*/
|
||||
export declare function setup(settings?: { vid: number, pid: number, mfrName?: string, prodName?: string }): void;
|
||||
export declare function setup(settings?: { vid: number, pid: number, mfrName?: string, prodName?: string, layout_path: string }): void;
|
||||
|
||||
/**
|
||||
* @brief Tells whether the virtual USB HID device has successfully connected
|
||||
@@ -79,3 +79,14 @@ export declare function print(string: string, delay?: number): void;
|
||||
* @param delay How many milliseconds to wait between key presses
|
||||
*/
|
||||
export declare function println(string: string, delay?: number): void;
|
||||
|
||||
/**
|
||||
* @brief Prints a string by Alt+Numpad method - works only on Windows!
|
||||
* @param string The string to print
|
||||
*/
|
||||
export declare function altPrintln(string: string): void;
|
||||
|
||||
/**
|
||||
* @brief Releases usb, Optional, but allows to interchange with usbdisk
|
||||
*/
|
||||
export declare function quit(): void;
|
||||
|
||||
@@ -116,6 +116,37 @@ Iso14443_4aError iso14443_4a_poller_send_block(
|
||||
return error;
|
||||
}
|
||||
|
||||
Iso14443_4aError iso14443_4a_poller_send_chain_block(
|
||||
Iso14443_4aPoller* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer) {
|
||||
iso14443_4_layer_set_i_block(instance->iso14443_4_layer, true, false);
|
||||
Iso14443_4aError error = iso14443_4a_poller_send_block(instance, tx_buffer, rx_buffer);
|
||||
return error;
|
||||
}
|
||||
|
||||
Iso14443_4aError iso14443_4a_poller_send_receive_ready_block(
|
||||
Iso14443_4aPoller* instance,
|
||||
bool acknowledged,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer) {
|
||||
bool CID_present = bit_buffer_get_size_bytes(tx_buffer) != 0;
|
||||
iso14443_4_layer_set_r_block(instance->iso14443_4_layer, acknowledged, CID_present);
|
||||
Iso14443_4aError error = iso14443_4a_poller_send_block(instance, tx_buffer, rx_buffer);
|
||||
return error;
|
||||
}
|
||||
|
||||
Iso14443_4aError iso14443_4a_poller_send_supervisory_block(
|
||||
Iso14443_4aPoller* instance,
|
||||
bool deselect,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer) {
|
||||
bool CID_present = bit_buffer_get_size_bytes(tx_buffer) != 0;
|
||||
iso14443_4_layer_set_s_block(instance->iso14443_4_layer, deselect, CID_present);
|
||||
Iso14443_4aError error = iso14443_4a_poller_send_block(instance, tx_buffer, rx_buffer);
|
||||
return error;
|
||||
}
|
||||
|
||||
Iso14443_4aError iso14443_4a_poller_send_block_pwt_ext(
|
||||
Iso14443_4aPoller* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
@@ -164,34 +195,3 @@ Iso14443_4aError iso14443_4a_poller_send_block_pwt_ext(
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
Iso14443_4aError iso14443_4a_poller_send_chain_block(
|
||||
Iso14443_4aPoller* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer) {
|
||||
iso14443_4_layer_set_i_block(instance->iso14443_4_layer, true, false);
|
||||
Iso14443_4aError error = iso14443_4a_poller_send_block(instance, tx_buffer, rx_buffer);
|
||||
return error;
|
||||
}
|
||||
|
||||
Iso14443_4aError iso14443_4a_poller_send_receive_ready_block(
|
||||
Iso14443_4aPoller* instance,
|
||||
bool acknowledged,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer) {
|
||||
bool CID_present = bit_buffer_get_size_bytes(tx_buffer) != 0;
|
||||
iso14443_4_layer_set_r_block(instance->iso14443_4_layer, acknowledged, CID_present);
|
||||
Iso14443_4aError error = iso14443_4a_poller_send_block(instance, tx_buffer, rx_buffer);
|
||||
return error;
|
||||
}
|
||||
|
||||
Iso14443_4aError iso14443_4a_poller_send_supervisory_block(
|
||||
Iso14443_4aPoller* instance,
|
||||
bool deselect,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer) {
|
||||
bool CID_present = bit_buffer_get_size_bytes(tx_buffer) != 0;
|
||||
iso14443_4_layer_set_s_block(instance->iso14443_4_layer, deselect, CID_present);
|
||||
Iso14443_4aError error = iso14443_4a_poller_send_block(instance, tx_buffer, rx_buffer);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -490,23 +490,12 @@ void subghz_protocol_decoder_gangqi_get_string(void* context, FuriString* output
|
||||
((instance->generic.data >> 24) & 0xFF) -
|
||||
((instance->generic.data >> 16) & 0xFF) - ((instance->generic.data >> 8) & 0xFF);
|
||||
|
||||
// Get 3 bytes sum
|
||||
uint16_t sum_3bytes_serial = ((instance->generic.serial >> 16) & 0xFF) +
|
||||
((instance->generic.serial >> 8) & 0xFF) +
|
||||
(instance->generic.serial & 0xFF);
|
||||
// Returns true if serial is valid
|
||||
bool serial_is_valid =
|
||||
(((!(sum_3bytes_serial & 0x3)) &&
|
||||
((0xB < sum_3bytes_serial) && (sum_3bytes_serial < 0x141))) &&
|
||||
(((instance->generic.serial >> 16) & 0xFF) <= 0x3));
|
||||
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"%s %db\r\n"
|
||||
"Key: 0x%X%08lX\r\n"
|
||||
"Serial: 0x%05lX CRC: 0x%02X\r\n"
|
||||
"Btn: 0x%01X - %s\r\n"
|
||||
"Serial is %s\r\n",
|
||||
"Btn: 0x%01X - %s\r\n",
|
||||
instance->generic.protocol_name,
|
||||
instance->generic.data_count_bit,
|
||||
(uint8_t)(instance->generic.data >> 32),
|
||||
@@ -514,6 +503,5 @@ void subghz_protocol_decoder_gangqi_get_string(void* context, FuriString* output
|
||||
instance->generic.serial,
|
||||
crc,
|
||||
instance->generic.btn,
|
||||
subghz_protocol_gangqi_get_button_name(instance->generic.btn),
|
||||
serial_is_valid ? "valid" : "invalid");
|
||||
subghz_protocol_gangqi_get_button_name(instance->generic.btn));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user