mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-24 13:52:38 +03:00
js modules updates
by Willy-JL and Sil333033
This commit is contained in:
parent
17dd089b5a
commit
d573cc06da
@ -86,3 +86,11 @@ App(
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_subghz/*.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_gpio",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_gpio_ep",
|
||||
requires=["js_app"],
|
||||
sources=["modules/js_gpio.c"],
|
||||
)
|
||||
|
@ -7,13 +7,16 @@ let dialog_params = ({
|
||||
header: "Test_header",
|
||||
text: "Test_text",
|
||||
button_left: "Left",
|
||||
button_right: "Right",
|
||||
button_right: "Files",
|
||||
button_center: "OK"
|
||||
});
|
||||
|
||||
let result2 = dialog.custom(dialog_params);
|
||||
if (result2 === "") {
|
||||
print("Back is pressed");
|
||||
} else if (result2 === "Files") {
|
||||
let result3 = dialog.pickFile("/ext", "*");
|
||||
print("Selected", result3);
|
||||
} else {
|
||||
print(result2, "is pressed");
|
||||
}
|
||||
|
62
applications/system/js_app/examples/apps/Scripts/gpio.js
Normal file
62
applications/system/js_app/examples/apps/Scripts/gpio.js
Normal file
@ -0,0 +1,62 @@
|
||||
let gpio = require("gpio");
|
||||
|
||||
// initialize pins
|
||||
gpio.init("PC3", "outputPushPull", "up"); // pin, mode, pull
|
||||
print("PC3 is initialized as outputPushPull with pull-up");
|
||||
|
||||
gpio.init("PC1", "input", "down"); // pin, mode, pull
|
||||
print("PC1 is initialized as input with pull-down");
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
// "input"
|
||||
// "outputPushPull"
|
||||
// "outputOpenDrain"
|
||||
// "altFunctionPushPull"
|
||||
// "altFunctionOpenDrain"
|
||||
// "analog"
|
||||
// "interruptRise"
|
||||
// "interruptFall"
|
||||
// "interruptRiseFall"
|
||||
// "eventRise"
|
||||
// "eventFall"
|
||||
// "eventRiseFall"
|
||||
|
||||
// possible pull
|
||||
// "no"
|
||||
// "up"
|
||||
// "down"
|
@ -1,6 +1,7 @@
|
||||
#include <core/common_defines.h>
|
||||
#include "../js_modules.h"
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
static bool js_dialog_msg_parse_params(struct mjs* mjs, const char** hdr, const char** msg) {
|
||||
size_t num_args = mjs_nargs(mjs);
|
||||
@ -128,10 +129,62 @@ static void js_dialog_custom(struct mjs* mjs) {
|
||||
}
|
||||
}
|
||||
|
||||
static void js_dialog_pick_file(struct mjs* mjs) {
|
||||
if(mjs_nargs(mjs) != 2) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Wrong arguments");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
mjs_val_t base_path_obj = mjs_arg(mjs, 0);
|
||||
if(!mjs_is_string(base_path_obj)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Base path must be a string");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
size_t base_path_len = 0;
|
||||
const char* base_path = mjs_get_string(mjs, &base_path_obj, &base_path_len);
|
||||
if((base_path_len == 0) || (base_path == NULL)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Bad base path argument");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
mjs_val_t extension_obj = mjs_arg(mjs, 1);
|
||||
if(!mjs_is_string(extension_obj)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Extension must be a string");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
size_t extension_len = 0;
|
||||
const char* extension = mjs_get_string(mjs, &extension_obj, &extension_len);
|
||||
if((extension_len == 0) || (extension == NULL)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Bad extension argument");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
const DialogsFileBrowserOptions browser_options = {
|
||||
.extension = extension,
|
||||
.icon = &I_Apps_10px,
|
||||
.base_path = base_path,
|
||||
};
|
||||
FuriString* path = furi_string_alloc_set(base_path);
|
||||
if(dialog_file_browser_show(dialogs, path, path, &browser_options)) {
|
||||
mjs_return(mjs, mjs_mk_string(mjs, furi_string_get_cstr(path), ~0, true));
|
||||
} else {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
furi_string_free(path);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
}
|
||||
|
||||
static void* js_dialog_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
mjs_val_t dialog_obj = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, dialog_obj, "message", ~0, MJS_MK_FN(js_dialog_message));
|
||||
mjs_set(mjs, dialog_obj, "custom", ~0, MJS_MK_FN(js_dialog_custom));
|
||||
mjs_set(mjs, dialog_obj, "pickFile", ~0, MJS_MK_FN(js_dialog_pick_file));
|
||||
*object = dialog_obj;
|
||||
|
||||
return (void*)1;
|
||||
|
272
applications/system/js_app/modules/js_gpio.c
Normal file
272
applications/system/js_app/modules/js_gpio.c
Normal file
@ -0,0 +1,272 @@
|
||||
#include "../js_modules.h"
|
||||
#include <furi_hal_gpio.h>
|
||||
#include <furi_hal_resources.h>
|
||||
#include <expansion/expansion.h>
|
||||
|
||||
typedef struct {
|
||||
const GpioPin* pin;
|
||||
const char* name;
|
||||
} GpioPinCtx;
|
||||
|
||||
static const GpioPinCtx js_gpio_pins[] = {
|
||||
{.pin = &gpio_ext_pa7, .name = "PA7"}, // 2
|
||||
{.pin = &gpio_ext_pa6, .name = "PA6"}, // 3
|
||||
{.pin = &gpio_ext_pa4, .name = "PA4"}, // 4
|
||||
{.pin = &gpio_ext_pb3, .name = "PB3"}, // 5
|
||||
{.pin = &gpio_ext_pb2, .name = "PB2"}, // 6
|
||||
{.pin = &gpio_ext_pc3, .name = "PC3"}, // 7
|
||||
{.pin = &gpio_swclk, .name = "PA14"}, // 10
|
||||
{.pin = &gpio_swdio, .name = "PA13"}, // 12
|
||||
{.pin = &gpio_usart_tx, .name = "PB6"}, // 13
|
||||
{.pin = &gpio_usart_rx, .name = "PB7"}, // 14
|
||||
{.pin = &gpio_ext_pc1, .name = "PC1"}, // 15
|
||||
{.pin = &gpio_ext_pc0, .name = "PC0"}, // 16
|
||||
{.pin = &gpio_ibutton, .name = "PB14"}, // 17
|
||||
};
|
||||
|
||||
bool js_gpio_get_gpio_pull(const char* pull, GpioPull* value) {
|
||||
if(strcmp(pull, "no") == 0) {
|
||||
*value = GpioPullNo;
|
||||
return true;
|
||||
} else if(strcmp(pull, "up") == 0) {
|
||||
*value = GpioPullUp;
|
||||
return true;
|
||||
} else if(strcmp(pull, "down") == 0) {
|
||||
*value = GpioPullDown;
|
||||
return true;
|
||||
} else {
|
||||
*value = GpioPullNo;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool js_gpio_get_gpio_mode(const char* mode, GpioMode* value) {
|
||||
if(strcmp(mode, "input") == 0) {
|
||||
*value = GpioModeInput;
|
||||
return true;
|
||||
} else if(strcmp(mode, "outputPushPull") == 0) {
|
||||
*value = GpioModeOutputPushPull;
|
||||
return true;
|
||||
} else if(strcmp(mode, "outputOpenDrain") == 0) {
|
||||
*value = GpioModeOutputOpenDrain;
|
||||
return true;
|
||||
} else if(strcmp(mode, "altFunctionPushPull") == 0) {
|
||||
*value = GpioModeAltFunctionPushPull;
|
||||
return true;
|
||||
} else if(strcmp(mode, "altFunctionOpenDrain") == 0) {
|
||||
*value = GpioModeAltFunctionOpenDrain;
|
||||
return true;
|
||||
} else if(strcmp(mode, "analog") == 0) {
|
||||
*value = GpioModeAnalog;
|
||||
return true;
|
||||
} else if(strcmp(mode, "interruptRise") == 0) {
|
||||
*value = GpioModeInterruptRise;
|
||||
return true;
|
||||
} else if(strcmp(mode, "interruptFall") == 0) {
|
||||
*value = GpioModeInterruptFall;
|
||||
return true;
|
||||
} else if(strcmp(mode, "interruptRiseFall") == 0) {
|
||||
*value = GpioModeInterruptRiseFall;
|
||||
return true;
|
||||
} else if(strcmp(mode, "eventRise") == 0) {
|
||||
*value = GpioModeEventRise;
|
||||
return true;
|
||||
} else if(strcmp(mode, "eventFall") == 0) {
|
||||
*value = GpioModeEventFall;
|
||||
return true;
|
||||
} else if(strcmp(mode, "eventRiseFall") == 0) {
|
||||
*value = GpioModeEventRiseFall;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const GpioPin* js_gpio_get_gpio_pin(const char* name) {
|
||||
for(size_t i = 0; i < COUNT_OF(js_gpio_pins); i++) {
|
||||
if(strcmp(js_gpio_pins[i].name, name) == 0) {
|
||||
return js_gpio_pins[i].pin;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void js_gpio_init(struct mjs* mjs) {
|
||||
mjs_val_t pin_arg = mjs_arg(mjs, 0);
|
||||
mjs_val_t mode_arg = mjs_arg(mjs, 1);
|
||||
mjs_val_t pull_arg = mjs_arg(mjs, 2);
|
||||
|
||||
if(!mjs_is_string(pin_arg)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a string");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* pin_name = mjs_get_string(mjs, &pin_arg, NULL);
|
||||
if(!pin_name) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Failed to get pin name");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mjs_is_string(mode_arg)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a string");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* mode_name = mjs_get_string(mjs, &mode_arg, NULL);
|
||||
if(!mode_name) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Failed to get mode name");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mjs_is_string(pull_arg)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a string");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* pull_name = mjs_get_string(mjs, &pull_arg, NULL);
|
||||
if(!pull_name) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Failed to get pull name");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
const GpioPin* gpio_pin = js_gpio_get_gpio_pin(pin_name);
|
||||
if(gpio_pin == NULL) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid pin name");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
GpioMode gpio_mode;
|
||||
if(!js_gpio_get_gpio_mode(mode_name, &gpio_mode)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid mode name");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
GpioPull gpio_pull;
|
||||
if(!js_gpio_get_gpio_pull(pull_name, &gpio_pull)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid pull name");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
expansion_disable(furi_record_open(RECORD_EXPANSION));
|
||||
furi_record_close(RECORD_EXPANSION);
|
||||
|
||||
furi_hal_gpio_init(gpio_pin, gpio_mode, gpio_pull, GpioSpeedVeryHigh);
|
||||
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
||||
static void js_gpio_write(struct mjs* mjs) {
|
||||
mjs_val_t pin_arg = mjs_arg(mjs, 0);
|
||||
mjs_val_t value_arg = mjs_arg(mjs, 1);
|
||||
|
||||
if(!mjs_is_string(pin_arg)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a string");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* pin_name = mjs_get_string(mjs, &pin_arg, NULL);
|
||||
if(!pin_name) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Failed to get pin name");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mjs_is_boolean(value_arg)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a boolean");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
bool value = mjs_get_bool(mjs, value_arg);
|
||||
|
||||
const GpioPin* gpio_pin = js_gpio_get_gpio_pin(pin_name);
|
||||
|
||||
if(gpio_pin == NULL) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid pin name");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
furi_hal_gpio_write(gpio_pin, value);
|
||||
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
||||
static void js_gpio_read(struct mjs* mjs) {
|
||||
mjs_val_t pin_arg = mjs_arg(mjs, 0);
|
||||
|
||||
if(!mjs_is_string(pin_arg)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a string");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* pin_name = mjs_get_string(mjs, &pin_arg, NULL);
|
||||
if(!pin_name) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Failed to get pin name");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
const GpioPin* gpio_pin = js_gpio_get_gpio_pin(pin_name);
|
||||
|
||||
if(gpio_pin == NULL) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid pin name");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
bool value = furi_hal_gpio_read(gpio_pin);
|
||||
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, value));
|
||||
}
|
||||
|
||||
static void* js_gpio_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
mjs_val_t gpio_obj = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, gpio_obj, "init", ~0, MJS_MK_FN(js_gpio_init));
|
||||
mjs_set(mjs, gpio_obj, "write", ~0, MJS_MK_FN(js_gpio_write));
|
||||
mjs_set(mjs, gpio_obj, "read", ~0, MJS_MK_FN(js_gpio_read));
|
||||
*object = gpio_obj;
|
||||
|
||||
return (void*)1;
|
||||
}
|
||||
|
||||
static void js_gpio_destroy(void* inst) {
|
||||
UNUSED(inst);
|
||||
|
||||
// loop through all pins and reset them to analog mode
|
||||
for(size_t i = 0; i < COUNT_OF(js_gpio_pins); i++) {
|
||||
furi_hal_gpio_write(js_gpio_pins[i].pin, false);
|
||||
furi_hal_gpio_init(js_gpio_pins[i].pin, GpioModeAnalog, GpioPullNo, GpioSpeedVeryHigh);
|
||||
}
|
||||
|
||||
expansion_enable(furi_record_open(RECORD_EXPANSION));
|
||||
furi_record_close(RECORD_EXPANSION);
|
||||
}
|
||||
|
||||
static const JsModuleDescriptor js_gpio_desc = {
|
||||
"gpio",
|
||||
js_gpio_create,
|
||||
js_gpio_destroy,
|
||||
};
|
||||
|
||||
static const FlipperAppPluginDescriptor plugin_descriptor = {
|
||||
.appid = PLUGIN_APP_ID,
|
||||
.ep_api_version = PLUGIN_API_VERSION,
|
||||
.entry_point = &js_gpio_desc,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* js_gpio_ep(void) {
|
||||
return &plugin_descriptor;
|
||||
}
|
Loading…
Reference in New Issue
Block a user