Skip to content

Commit 46a7616

Browse files
Sil333033RogueMaster
authored andcommitted
Latest Release RM0311-1604-0.99.2-1289018 on PATREON & GitHub - JS: added GPIO module
1 parent 57c25b7 commit 46a7616

File tree

4 files changed

+310
-2
lines changed

4 files changed

+310
-2
lines changed

ReadMe.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ This software is for experimental purposes only and is not meant for any illegal
2929

3030
## Latest Updates - [PATREON: Latest Release RM0311-1604-0.99.2-1289018](https://www.patreon.com/RogueMaster?filters[tag]=Latest%20Release)
3131

32-
- Last Synced/Checked OFW, changes in [commits](https://github.com/flipperdevices/flipperzero-firmware/commits/dev): `2024-03-11 16:04 EST`
33-
- Last Synced/Checked Unleashed, changes in [changelog](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/CHANGELOG.md): `2024-03-11 16:04 EST`
32+
- Last Synced/Checked OFW, changes in [commits](https://github.com/flipperdevices/flipperzero-firmware/commits/dev): `2024-03-11 17:30 EST`
33+
- Last Synced/Checked Unleashed, changes in [changelog](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/CHANGELOG.md): `2024-03-11 17:30 EST`
3434
- Updated: [J305 Geiger Counter v1.2 (By nmrr)](https://github.com/nmrr/flipperzero-geigercounter)
35+
- Updated: [JS Runner v1.0 (By nminaylov & DrZlo13)-OFW](https://github.com/flipperdevices/flipperzero-firmware/pull/3286) [JS: added GPIO module (By Sil333033)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/db087e1c7b8bf6aae157bd1738801742614b6d36)
3536

3637
<a name="release">
3738

applications/system/js_app/application.fam

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,11 @@ App(
110110
requires=["js_app"],
111111
sources=["modules/js_subghz/*.c"],
112112
)
113+
114+
App(
115+
appid="js_gpio",
116+
apptype=FlipperAppType.PLUGIN,
117+
entry_point="js_gpio_ep",
118+
requires=["js_app"],
119+
sources=["modules/js_gpio.c"],
120+
)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
let gpio = require("gpio");
2+
3+
// initialize pins
4+
gpio.init("PC3", "outputPushPull", "up"); // pin, mode, pull
5+
print("PC3 is initialized as outputPushPull with pull-up");
6+
7+
gpio.init("PC1", "input", "down"); // pin, mode, pull
8+
print("PC1 is initialized as input with pull-down");
9+
10+
// let led on PC3 blink
11+
gpio.write("PC3", true); // high
12+
delay(1000);
13+
gpio.write("PC3", false); // low
14+
delay(1000);
15+
gpio.write("PC3", true); // high
16+
delay(1000);
17+
gpio.write("PC3", false); // low
18+
19+
// read value from PC1 and write it to PC3
20+
while (true) {
21+
let value = gpio.read("PC1");
22+
gpio.write("PC3", value);
23+
24+
value ? print("PC1 is high") : print("PC1 is low");
25+
26+
delay(100);
27+
}
28+
29+
30+
// possible pins https://docs.flipper.net/gpio-and-modules#miFsS
31+
// "PA7" aka 2
32+
// "PA6" aka 3
33+
// "PA4" aka 4
34+
// "PB3" aka 5
35+
// "PB2" aka 6
36+
// "PC3" aka 7
37+
// "PA14" aka 10
38+
// "PA13" aka 12
39+
// "PB6" aka 13
40+
// "PB7" aka 14
41+
// "PC1" aka 15
42+
// "PC0" aka 16
43+
// "PB14" aka 17
44+
45+
// possible modes
46+
// "input"
47+
// "outputPushPull"
48+
// "outputOpenDrain"
49+
// "altFunctionPushPull"
50+
// "altFunctionOpenDrain"
51+
// "analog"
52+
// "interruptRise"
53+
// "interruptFall"
54+
// "interruptRiseFall"
55+
// "eventRise"
56+
// "eventFall"
57+
// "eventRiseFall"
58+
59+
// possible pull
60+
// "no"
61+
// "up"
62+
// "down"
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
#include "../js_modules.h"
2+
#include <furi_hal_gpio.h>
3+
#include <furi_hal_resources.h>
4+
5+
typedef struct {
6+
const GpioPin* pin;
7+
const char* name;
8+
} GpioPinCtx;
9+
10+
static const GpioPinCtx js_gpio_pins[] = {
11+
{.pin = &gpio_ext_pa7, .name = "PA7"}, // 2
12+
{.pin = &gpio_ext_pa6, .name = "PA6"}, // 3
13+
{.pin = &gpio_ext_pa4, .name = "PA4"}, // 4
14+
{.pin = &gpio_ext_pb3, .name = "PB3"}, // 5
15+
{.pin = &gpio_ext_pb2, .name = "PB2"}, // 6
16+
{.pin = &gpio_ext_pc3, .name = "PC3"}, // 7
17+
{.pin = &gpio_swclk, .name = "PA14"}, // 10
18+
{.pin = &gpio_swdio, .name = "PA13"}, // 12
19+
{.pin = &gpio_usart_tx, .name = "PB6"}, // 13
20+
{.pin = &gpio_usart_rx, .name = "PB7"}, // 14
21+
{.pin = &gpio_ext_pc1, .name = "PC1"}, // 15
22+
{.pin = &gpio_ext_pc0, .name = "PC0"}, // 16
23+
{.pin = &gpio_ibutton, .name = "PB14"}, // 17
24+
};
25+
26+
GpioPull js_gpio_get_gpio_pull(const char* pull) {
27+
if(strcmp(pull, "no") == 0) {
28+
return GpioPullNo;
29+
} else if(strcmp(pull, "up") == 0) {
30+
return GpioPullUp;
31+
} else if(strcmp(pull, "down") == 0) {
32+
return GpioPullDown;
33+
} else {
34+
return GpioPullNo;
35+
}
36+
}
37+
38+
GpioMode js_gpio_get_gpio_mode(const char* mode) {
39+
if(strcmp(mode, "input") == 0) {
40+
return GpioModeInput;
41+
} else if(strcmp(mode, "outputPushPull") == 0) {
42+
return GpioModeOutputPushPull;
43+
} else if(strcmp(mode, "outputOpenDrain") == 0) {
44+
return GpioModeOutputOpenDrain;
45+
} else if(strcmp(mode, "altFunctionPushPull") == 0) {
46+
return GpioModeAltFunctionPushPull;
47+
} else if(strcmp(mode, "altFunctionOpenDrain") == 0) {
48+
return GpioModeAltFunctionOpenDrain;
49+
} else if(strcmp(mode, "analog") == 0) {
50+
return GpioModeAnalog;
51+
} else if(strcmp(mode, "interruptRise") == 0) {
52+
return GpioModeInterruptRise;
53+
} else if(strcmp(mode, "interruptFall") == 0) {
54+
return GpioModeInterruptFall;
55+
} else if(strcmp(mode, "interruptRiseFall") == 0) {
56+
return GpioModeInterruptRiseFall;
57+
} else if(strcmp(mode, "eventRise") == 0) {
58+
return GpioModeEventRise;
59+
} else if(strcmp(mode, "eventFall") == 0) {
60+
return GpioModeEventFall;
61+
} else if(strcmp(mode, "eventRiseFall") == 0) {
62+
return GpioModeEventRiseFall;
63+
} else {
64+
return GpioModeInput;
65+
}
66+
}
67+
68+
const GpioPin* js_gpio_get_gpio_pin(const char* name) {
69+
for(int i = 0; i < 12; i++) {
70+
if(strcmp(js_gpio_pins[i].name, name) == 0) {
71+
return js_gpio_pins[i].pin;
72+
}
73+
}
74+
return NULL;
75+
}
76+
77+
static void js_gpio_init(struct mjs* mjs) {
78+
mjs_val_t pin_arg = mjs_arg(mjs, 0);
79+
mjs_val_t mode_arg = mjs_arg(mjs, 1);
80+
mjs_val_t pull_arg = mjs_arg(mjs, 2);
81+
82+
if(!mjs_is_string(pin_arg)) {
83+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a string");
84+
mjs_return(mjs, MJS_UNDEFINED);
85+
return;
86+
}
87+
88+
const char* pin_name = mjs_get_string(mjs, &pin_arg, NULL);
89+
if(!pin_name) {
90+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Failed to get pin name");
91+
mjs_return(mjs, MJS_UNDEFINED);
92+
return;
93+
}
94+
95+
if(!mjs_is_string(mode_arg)) {
96+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a string");
97+
mjs_return(mjs, MJS_UNDEFINED);
98+
return;
99+
}
100+
101+
const char* mode_name = mjs_get_string(mjs, &mode_arg, NULL);
102+
if(!mode_name) {
103+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Failed to get mode name");
104+
mjs_return(mjs, MJS_UNDEFINED);
105+
return;
106+
}
107+
108+
if(!mjs_is_string(pull_arg)) {
109+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a string");
110+
mjs_return(mjs, MJS_UNDEFINED);
111+
return;
112+
}
113+
114+
const char* pull_name = mjs_get_string(mjs, &pull_arg, NULL);
115+
if(!pull_name) {
116+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Failed to get pull name");
117+
mjs_return(mjs, MJS_UNDEFINED);
118+
return;
119+
}
120+
121+
const GpioPin* gpio_pin = js_gpio_get_gpio_pin(pin_name);
122+
const GpioMode gpio_mode = js_gpio_get_gpio_mode(mode_name);
123+
const GpioPull gpio_pull = js_gpio_get_gpio_pull(pull_name);
124+
125+
if(gpio_pin == NULL) {
126+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid pin name");
127+
mjs_return(mjs, MJS_UNDEFINED);
128+
return;
129+
}
130+
131+
furi_hal_gpio_init(gpio_pin, gpio_mode, gpio_pull, GpioSpeedVeryHigh);
132+
133+
mjs_return(mjs, MJS_UNDEFINED);
134+
}
135+
136+
static void js_gpio_write(struct mjs* mjs) {
137+
mjs_val_t pin_arg = mjs_arg(mjs, 0);
138+
mjs_val_t value_arg = mjs_arg(mjs, 1);
139+
140+
if(!mjs_is_string(pin_arg)) {
141+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a string");
142+
mjs_return(mjs, MJS_UNDEFINED);
143+
return;
144+
}
145+
146+
const char* pin_name = mjs_get_string(mjs, &pin_arg, NULL);
147+
if(!pin_name) {
148+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Failed to get pin name");
149+
mjs_return(mjs, MJS_UNDEFINED);
150+
return;
151+
}
152+
153+
if(!mjs_is_boolean(value_arg)) {
154+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a boolean");
155+
mjs_return(mjs, MJS_UNDEFINED);
156+
return;
157+
}
158+
159+
bool value = mjs_get_bool(mjs, value_arg);
160+
161+
const GpioPin* gpio_pin = js_gpio_get_gpio_pin(pin_name);
162+
163+
if(gpio_pin == NULL) {
164+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid pin name");
165+
mjs_return(mjs, MJS_UNDEFINED);
166+
return;
167+
}
168+
169+
furi_hal_gpio_write(gpio_pin, value);
170+
171+
mjs_return(mjs, MJS_UNDEFINED);
172+
}
173+
174+
static void js_gpio_read(struct mjs* mjs) {
175+
mjs_val_t pin_arg = mjs_arg(mjs, 0);
176+
177+
if(!mjs_is_string(pin_arg)) {
178+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a string");
179+
mjs_return(mjs, MJS_UNDEFINED);
180+
return;
181+
}
182+
183+
const char* pin_name = mjs_get_string(mjs, &pin_arg, NULL);
184+
if(!pin_name) {
185+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Failed to get pin name");
186+
mjs_return(mjs, MJS_UNDEFINED);
187+
return;
188+
}
189+
190+
const GpioPin* gpio_pin = js_gpio_get_gpio_pin(pin_name);
191+
192+
if(gpio_pin == NULL) {
193+
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid pin name");
194+
mjs_return(mjs, MJS_UNDEFINED);
195+
return;
196+
}
197+
198+
bool value = furi_hal_gpio_read(gpio_pin);
199+
200+
mjs_return(mjs, mjs_mk_boolean(mjs, value));
201+
}
202+
203+
static void* js_gpio_create(struct mjs* mjs, mjs_val_t* object) {
204+
mjs_val_t gpio_obj = mjs_mk_object(mjs);
205+
mjs_set(mjs, gpio_obj, "init", ~0, MJS_MK_FN(js_gpio_init));
206+
mjs_set(mjs, gpio_obj, "write", ~0, MJS_MK_FN(js_gpio_write));
207+
mjs_set(mjs, gpio_obj, "read", ~0, MJS_MK_FN(js_gpio_read));
208+
*object = gpio_obj;
209+
210+
return (void*)1;
211+
}
212+
213+
static void js_gpio_destroy(void* inst) {
214+
UNUSED(inst);
215+
216+
// loop through all pins and reset them to analog mode
217+
for(int i = 0; i < 12; i++) {
218+
furi_hal_gpio_write(js_gpio_pins[i].pin, false);
219+
furi_hal_gpio_init(js_gpio_pins[i].pin, GpioModeAnalog, GpioPullNo, GpioSpeedVeryHigh);
220+
}
221+
}
222+
223+
static const JsModuleDescriptor js_gpio_desc = {
224+
"gpio",
225+
js_gpio_create,
226+
js_gpio_destroy,
227+
};
228+
229+
static const FlipperAppPluginDescriptor plugin_descriptor = {
230+
.appid = PLUGIN_APP_ID,
231+
.ep_api_version = PLUGIN_API_VERSION,
232+
.entry_point = &js_gpio_desc,
233+
};
234+
235+
const FlipperAppPluginDescriptor* js_gpio_ep(void) {
236+
return &plugin_descriptor;
237+
}

0 commit comments

Comments
 (0)