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