1 /*
2 * Copyright (C) 2015-2019 Alibaba Group Holding Limited
3 */
4
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8
9 #include "amp_config.h"
10 #include "amp_defines.h"
11 #include "aos_hal_gpio.h"
12 #include "aos_system.h"
13 #include "amp_task.h"
14 #include "board_mgr.h"
15 #include "quickjs.h"
16 #include "quickjs_addon_common.h"
17
18 #define MOD_STR "GPIO"
19
20 #define GPIO_IRQ_RISING_EDGE "rising"
21 #define GPIO_IRQ_FALLING_EDGE "falling"
22 #define GPIO_IRQ_BOTH_EDGE "both"
23
24 static uint16_t gpio_init_flag = 0;
25 static JSClassID js_gpio_class_id;
26
native_gpio_open(JSContext * ctx,JSValueConst this_val,int argc,JSValueConst * argv)27 static JSValue native_gpio_open(JSContext *ctx, JSValueConst this_val,
28 int argc, JSValueConst *argv)
29 {
30 int8_t ret = -1;
31 item_handle_t gpio_handle;
32 gpio_handle.handle = NULL;
33 gpio_dev_t *gpio_device = NULL;
34
35 const char *id = JS_ToCString(ctx, argv[0]);
36 if (id == NULL) {
37 amp_error(MOD_STR, "get gpio id fail!");
38 goto out;
39 }
40
41 ret = board_attach_item(MODULE_GPIO, id, &gpio_handle);
42 if (0 != ret) {
43 amp_error(MOD_STR, "board_attach_item fail!, id %s", id);
44 goto out;
45 }
46
47 amp_debug(MOD_STR, "gpio handle:%p\n", gpio_handle.handle);
48 gpio_device = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
49 if (NULL == gpio_device) {
50 amp_error(MOD_STR, "board_get_node_by_handle fail!");
51 goto out;
52 }
53
54 if (gpio_init_flag & (1 << gpio_device->port)) {
55 amp_debug(MOD_STR, "gpio port [%d] is already inited", gpio_device->port);
56 goto out;
57 }
58
59 ret = aos_hal_gpio_init(gpio_device);
60 if (0 != ret) {
61 amp_error(MOD_STR, "aos_hal_gpio_init fail!");
62 goto out;
63 }
64
65 gpio_init_flag |= (1 << gpio_device->port);
66
67 out:
68 if (id != NULL) {
69 JS_FreeCString(ctx, id);
70 }
71 if (0 != ret) {
72 JS_SetContextOpaque(ctx, NULL);
73 board_disattach_item(MODULE_GPIO, &gpio_handle);
74 } else {
75 JSValue obj;
76 obj = JS_NewObjectClass(ctx, js_gpio_class_id);
77 JS_SetOpaque(obj, (void *)gpio_handle.handle);
78 return obj;
79 }
80 return JS_NewInt32(ctx, ret);
81 }
82
native_gpio_close(JSContext * ctx,JSValueConst this_val,int argc,JSValueConst * argv)83 static JSValue native_gpio_close(JSContext *ctx, JSValueConst this_val,
84 int argc, JSValueConst *argv)
85 {
86 int32_t ret = -1;
87 item_handle_t gpio_handle;
88 gpio_dev_t *gpio_device = NULL;
89 gpio_params_t *priv = NULL;
90
91 gpio_handle.handle = JS_GetOpaque2(ctx, this_val, js_gpio_class_id);
92 if (!gpio_handle.handle) {
93 amp_warn(MOD_STR, "parameter must be handle");
94 goto out;
95 }
96
97 gpio_device = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
98 if (NULL == gpio_device) {
99 amp_error(MOD_STR, "board_get_node_by_handle fail!");
100 goto out;
101 }
102 priv = (gpio_params_t *)gpio_device->priv;
103 if(priv->reserved != NULL) {
104 aos_printf("func %p free memory %p \n", __func__, priv->reserved);
105 aos_free(priv->reserved);
106 priv->reserved = NULL;
107 }
108 ret = aos_hal_gpio_finalize(gpio_device);
109 if (0 != ret) {
110 amp_error(MOD_STR, "aos_hal_gpio_finalize fail!");
111 goto out;
112 }
113 board_disattach_item(MODULE_GPIO, &gpio_handle);
114
115 out:
116 return JS_NewInt32(ctx, ret);
117 }
118
native_gpio_toggle(JSContext * ctx,JSValueConst this_val,int argc,JSValueConst * argv)119 static JSValue native_gpio_toggle(JSContext *ctx, JSValueConst this_val,
120 int argc, JSValueConst *argv)
121 {
122 int32_t ret = -1;
123 item_handle_t gpio_handle;
124 gpio_dev_t *gpio_device = NULL;
125
126 gpio_handle.handle = JS_GetOpaque2(ctx, this_val, js_gpio_class_id);
127 if (!gpio_handle.handle) {
128 amp_warn(MOD_STR, "parameter must be handle");
129 goto out;
130 }
131 gpio_device = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
132 if (NULL == gpio_device) {
133 amp_error(MOD_STR, "board_get_node_by_handle fail!");
134 goto out;
135 }
136
137 ret = aos_hal_gpio_output_toggle(gpio_device);
138
139 out:
140 return JS_NewInt32(ctx, ret);
141 }
142
native_gpio_write(JSContext * ctx,JSValueConst this_val,int argc,JSValueConst * argv)143 static JSValue native_gpio_write(JSContext *ctx, JSValueConst this_val,
144 int argc, JSValueConst *argv)
145 {
146 int8_t ret = -1;
147 int8_t result = -1;
148 int8_t level = 0;
149 item_handle_t gpio_handle;
150 gpio_dev_t *gpio_device = NULL;
151
152 gpio_handle.handle = JS_GetOpaque2(ctx, this_val, js_gpio_class_id);
153 if (!gpio_handle.handle) {
154 amp_warn(MOD_STR, "parameter must be handle");
155 goto out;
156 }
157
158 gpio_device = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
159 if (NULL == gpio_device) {
160 amp_error(MOD_STR, "board_get_node_by_handle fail!");
161 goto out;
162 }
163 JS_ToInt32(ctx, &level, argv[0]);
164 if (level) {
165 ret = aos_hal_gpio_output_high(gpio_device);
166 } else {
167 ret = aos_hal_gpio_output_low(gpio_device);
168 }
169 if (-1 == ret) {
170 amp_error(MOD_STR, "gpio output set fail!");
171 goto out;
172 }
173 result = 0;
174 out:
175 return JS_NewInt32(ctx, result);
176 }
177
native_gpio_read(JSContext * ctx,JSValueConst this_val,int argc,JSValueConst * argv)178 static JSValue native_gpio_read(JSContext *ctx, JSValueConst this_val,
179 int argc, JSValueConst *argv)
180 {
181 item_handle_t gpio_handle;
182 uint32_t level = 0;
183 gpio_dev_t *gpio_device = NULL;
184
185 gpio_handle.handle = JS_GetOpaque2(ctx, this_val, js_gpio_class_id);
186 if (!gpio_handle.handle) {
187 amp_warn(MOD_STR, "parameter must be handle");
188 goto out;
189 }
190
191 gpio_device = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
192 if (NULL == gpio_device) {
193 amp_error(MOD_STR, "board_get_node_by_handle fail!");
194 goto out;
195 }
196 aos_hal_gpio_input_get(gpio_device, &level);
197 out:
198 return JS_NewInt32(ctx, level);
199 }
200
201 typedef struct {
202 JSValue js_cb_ref;
203 gpio_dev_t *dev;
204 }gpio_irq_notify_param_t;
205
gpio_irq_notify(void * arg)206 static void gpio_irq_notify(void *arg)
207 {
208 gpio_irq_notify_param_t *param = (gpio_irq_notify_param_t *)arg;
209 JSContext *ctx = js_get_context();
210 uint32_t value = 0;
211
212 aos_hal_gpio_input_get(param->dev, &value);
213 JSValue v = JS_NewInt32(ctx, value);
214 JSValue val = JS_Call(ctx, param->js_cb_ref, JS_UNDEFINED, 1, &v);
215
216 JS_FreeValue(ctx, v);
217 JS_FreeValue(ctx, val);
218
219 aos_free(param);
220 }
221
222 /* avoid stdout in irq function */
gpio_irq(void * arg)223 static void gpio_irq(void *arg)
224 {
225 static uint64_t irq_lasttime = 0;
226 uint64_t irq_nowtime = aos_now_ms();
227 gpio_irq_notify_param_t *notify = aos_malloc(sizeof(gpio_irq_notify_param_t));
228
229 if ((NULL == notify) || (NULL == arg)) {
230 /* amp_error(MOD_STR, "param error!\n"); */
231 return;
232 }
233
234 memcpy(notify, (gpio_irq_notify_param_t *)arg, sizeof(gpio_irq_notify_param_t));
235 if(irq_nowtime - irq_lasttime < 200) {
236 // demounce in 200ms
237 return;
238 }
239 irq_lasttime = irq_nowtime;
240 if (amp_task_schedule_call(gpio_irq_notify, notify) < 0) {
241 /* amp_warn(MOD_STR, "amp_task_schedule_call failed\n"); */
242 }
243 }
244
native_gpio_on(JSContext * ctx,JSValueConst this_val,int argc,JSValueConst * argv)245 static JSValue native_gpio_on(JSContext *ctx, JSValueConst this_val,
246 int argc, JSValueConst *argv)
247 {
248 int8_t ret = -1;
249 int8_t result = -1;
250 int8_t irq_edge = 0;
251 item_handle_t gpio_handle;
252 gpio_handle.handle = NULL;
253 gpio_dev_t *gpio_device = NULL;
254 gpio_params_t *priv = NULL;
255 const char *edge;
256 gpio_irq_notify_param_t *notify = NULL;
257
258 notify = aos_malloc(sizeof(gpio_irq_notify_param_t));
259 aos_printf("func %p alloc memory %p \n", __func__, notify);
260 if (!notify)
261 goto out;
262
263 gpio_handle.handle = JS_GetOpaque2(ctx, this_val, js_gpio_class_id);
264 if (!gpio_handle.handle) {
265 amp_warn(MOD_STR, "parameter must be handle");
266 aos_free(notify);
267 goto out;
268 }
269 gpio_device = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
270 if (NULL == gpio_device) {
271 amp_error(MOD_STR, "board_get_node_by_handle fail!");
272 aos_free(notify);
273 goto out;
274 }
275
276 priv = (gpio_params_t *)gpio_device->priv;
277 priv->reserved = (void *)notify; // 停止中断时,释放该内存
278 irq_edge = priv->irq_mode;
279 JSValue irq_cb = argv[0];
280 if (!JS_IsFunction(ctx, irq_cb)) {
281 return JS_ThrowTypeError(ctx, "not a function");
282 }
283 notify->js_cb_ref = JS_DupValue(ctx, irq_cb);
284 notify->dev = gpio_device;
285
286 // amp_debug(MOD_STR, "%p, irq_edge:%04x port:%d", gpio_device, irq_edge, gpio_device->port);
287 ret = aos_hal_gpio_enable_irq(gpio_device, irq_edge, gpio_irq, notify);
288 if (ret < 0) {
289 amp_error(MOD_STR, "aos_hal_gpio_enable_irq fail!");
290 goto out;
291 }
292
293 result = 0;
294
295 out:
296 return JS_NewInt32(ctx, result);
297 }
298
299 static JSClassDef js_gpio_class = {
300 "GPIO",
301 };
302
303 static const JSCFunctionListEntry js_gpio_funcs[] = {
304 JS_CFUNC_DEF("open", 1, native_gpio_open ),
305 JS_CFUNC_DEF("read", 0, native_gpio_read ),
306 JS_CFUNC_DEF("write", 1, native_gpio_write ),
307 JS_CFUNC_DEF("toggle", 0, native_gpio_toggle),
308 JS_CFUNC_DEF("on", 0, native_gpio_on),
309 JS_CFUNC_DEF("close", 0, native_gpio_close ),
310 };
311
js_gpio_init(JSContext * ctx,JSModuleDef * m)312 static int js_gpio_init(JSContext *ctx, JSModuleDef *m)
313 {
314 JSValue proto;
315
316 JS_NewClassID(&js_gpio_class_id);
317
318 JS_NewClass(JS_GetRuntime(ctx), js_gpio_class_id, &js_gpio_class);
319 proto = JS_NewObject(ctx);
320 JS_SetPropertyFunctionList(ctx, proto, js_gpio_funcs,
321 countof(js_gpio_funcs));
322 JS_SetClassProto(ctx, js_gpio_class_id, proto);
323
324 return JS_SetModuleExportList(ctx, m, js_gpio_funcs,
325 countof(js_gpio_funcs));
326 }
327
js_init_module_gpio(JSContext * ctx,const char * module_name)328 JSModuleDef *js_init_module_gpio(JSContext *ctx, const char *module_name)
329 {
330 JSModuleDef *m;
331 m = JS_NewCModule(ctx, module_name, js_gpio_init);
332 if (!m)
333 return NULL;
334 JS_AddModuleExportList(ctx, m, js_gpio_funcs, countof(js_gpio_funcs));
335 return m;
336 }
337
module_gpio_register(void)338 void module_gpio_register(void)
339 {
340 amp_debug(MOD_STR, "module_gpio_register");
341 JSContext *ctx = js_get_context();
342 aos_printf("module gpio register\n");
343 js_init_module_gpio(ctx, "GPIO");
344 }
345