Skip to content

Commit

Permalink
JS: added GPIO module
Browse files Browse the repository at this point in the history
  • Loading branch information
Sil333033 committed Mar 11, 2024
1 parent 400351d commit d947fa7
Show file tree
Hide file tree
Showing 3 changed files with 308 additions and 0 deletions.
9 changes: 9 additions & 0 deletions applications/system/js_app/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,19 @@ App(
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_gpio",
apptype=FlipperAppType.PLUGIN,
entry_point="js_gpio_ep",
requires=["js_app"],
sources=["modules/js_gpio.c"],
)
62 changes: 62 additions & 0 deletions applications/system/js_app/examples/apps/Scripts/gpio.js
Original file line number Diff line number Diff line change
@@ -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"
237 changes: 237 additions & 0 deletions applications/system/js_app/modules/js_gpio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
#include "../js_modules.h"
#include <furi_hal_gpio.h>
#include <furi_hal_resources.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
};

GpioPull js_gpio_get_gpio_pull(const char* pull) {
if(strcmp(pull, "no") == 0) {
return GpioPullNo;
} else if(strcmp(pull, "up") == 0) {
return GpioPullUp;
} else if(strcmp(pull, "down") == 0) {
return GpioPullDown;
} else {
return GpioPullNo;
}
}

GpioMode js_gpio_get_gpio_mode(const char* mode) {
if(strcmp(mode, "input") == 0) {
return GpioModeInput;
} else if(strcmp(mode, "outputPushPull") == 0) {
return GpioModeOutputPushPull;
} else if(strcmp(mode, "outputOpenDrain") == 0) {
return GpioModeOutputOpenDrain;
} else if(strcmp(mode, "altFunctionPushPull") == 0) {
return GpioModeAltFunctionPushPull;
} else if(strcmp(mode, "altFunctionOpenDrain") == 0) {
return GpioModeAltFunctionOpenDrain;
} else if(strcmp(mode, "analog") == 0) {
return GpioModeAnalog;
} else if(strcmp(mode, "interruptRise") == 0) {
return GpioModeInterruptRise;
} else if(strcmp(mode, "interruptFall") == 0) {
return GpioModeInterruptFall;
} else if(strcmp(mode, "interruptRiseFall") == 0) {
return GpioModeInterruptRiseFall;
} else if(strcmp(mode, "eventRise") == 0) {
return GpioModeEventRise;
} else if(strcmp(mode, "eventFall") == 0) {
return GpioModeEventFall;
} else if(strcmp(mode, "eventRiseFall") == 0) {
return GpioModeEventRiseFall;
} else {
return GpioModeInput;
}
}

const GpioPin* js_gpio_get_gpio_pin(const char* name) {
for(int i = 0; i < 12; 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);
const GpioMode gpio_mode = js_gpio_get_gpio_mode(mode_name);
const GpioPull gpio_pull = js_gpio_get_gpio_pull(pull_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_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(int i = 0; i < 12; i++) {
furi_hal_gpio_write(js_gpio_pins[i].pin, false);
furi_hal_gpio_init(js_gpio_pins[i].pin, GpioModeAnalog, GpioPullNo, GpioSpeedVeryHigh);
}
}

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;
}

0 comments on commit d947fa7

Please sign in to comment.