1 /*
2  * Copyright (C) 2015-2019 Alibaba Group Holding Limited
3  */
4 
5 #include <stdint.h>
6 
7 #include "amp_config.h"
8 #include "amp_defines.h"
9 #include "aos_hal_gpio.h"
10 #include "aos_system.h"
11 #include "amp_task.h"
12 #include "board_mgr.h"
13 #include "be_inl.h"
14 
15 #define MOD_STR "GPIO"
16 
17 #define GPIO_IRQ_RISING_EDGE "rising"
18 #define GPIO_IRQ_FALLING_EDGE "falling"
19 #define GPIO_IRQ_BOTH_EDGE "both"
20 
21 static uint16_t gpio_init_flag = 0;
native_gpio_open(duk_context * ctx)22 static duk_ret_t native_gpio_open(duk_context *ctx)
23 {
24     int8_t ret = -1;
25     item_handle_t gpio_handle;
26     gpio_handle.handle      = NULL;
27     gpio_dev_t *gpio_device = NULL;
28 
29     if (!duk_is_string(ctx, 0)) {
30         amp_warn(MOD_STR, "parameter must be string");
31         goto out;
32     }
33     const char *id = duk_get_string(ctx, 0);
34     ret = board_attach_item(MODULE_GPIO, id, &gpio_handle);
35     if (0 != ret) {
36         amp_error(MOD_STR, "board_attach_item fail!, id %s", id);
37         goto out;
38     }
39     amp_debug(MOD_STR, "gpio handle:%p\n", gpio_handle.handle);
40     gpio_device = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
41     if (NULL == gpio_device) {
42         amp_error(MOD_STR, "board_get_node_by_handle fail!");
43         goto out;
44     }
45 
46     if (gpio_init_flag & (1 << gpio_device->port)) {
47         amp_debug(MOD_STR, "gpio port [%d] is already inited", gpio_device->port);
48         goto out;
49     }
50     ret = aos_hal_gpio_init(gpio_device);
51     if (0 != ret) {
52         amp_error(MOD_STR, "aos_hal_gpio_init fail!");
53         goto out;
54     }
55     // gpio_device->priv = NULL;
56     gpio_init_flag |= (1 << gpio_device->port);
57 
58 out:
59     if (0 != ret) {
60         duk_push_pointer(ctx, NULL);
61         board_disattach_item(MODULE_GPIO, &gpio_handle);
62     } else {
63         duk_push_pointer(ctx, (void *)gpio_handle.handle);
64     }
65     return 1;
66 }
67 
native_gpio_close(duk_context * ctx)68 static duk_ret_t native_gpio_close(duk_context *ctx)
69 {
70     int32_t ret = -1;
71     item_handle_t gpio_handle;
72     gpio_dev_t *gpio_device = NULL;
73 
74     if (!duk_is_pointer(ctx, 0)) {
75         amp_warn(MOD_STR, "parameter must be handle");
76         goto out;
77     }
78     gpio_handle.handle = duk_get_pointer(ctx, 0);
79     gpio_device        = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
80     if (NULL == gpio_device) {
81         amp_error(MOD_STR, "board_get_node_by_handle fail!");
82         goto out;
83     }
84     ret = aos_hal_gpio_finalize(gpio_device);
85     if (0 != ret) {
86         amp_error(MOD_STR, "aos_hal_gpio_finalize fail!");
87         goto out;
88     }
89     board_disattach_item(MODULE_GPIO, &gpio_handle);
90 
91 out:
92     duk_push_int(ctx, ret);
93     return 1;
94 }
95 
native_gpio_toggle(duk_context * ctx)96 static duk_ret_t native_gpio_toggle(duk_context *ctx)
97 {
98     int32_t ret = -1;
99     item_handle_t gpio_handle;
100     gpio_dev_t *gpio_device = NULL;
101 
102     if (!duk_is_pointer(ctx, 0)) {
103         amp_warn(MOD_STR, "parameter must be handle");
104         goto out;
105     }
106     gpio_handle.handle = duk_get_pointer(ctx, 0);
107     gpio_device        = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
108     if (NULL == gpio_device) {
109         amp_error(MOD_STR, "board_get_node_by_handle fail!");
110         goto out;
111     }
112 
113     ret = aos_hal_gpio_output_toggle(gpio_device);
114 
115 out:
116     duk_push_int(ctx, ret);
117     return 1;
118 }
119 
native_gpio_write(duk_context * ctx)120 static duk_ret_t native_gpio_write(duk_context *ctx)
121 {
122     int8_t ret    = -1;
123     int8_t result = -1;
124     int8_t level  = 0;
125     item_handle_t gpio_handle;
126     gpio_dev_t *gpio_device = NULL;
127 
128     if (!duk_is_pointer(ctx, 0) || !duk_is_number(ctx, 1)) {
129         amp_warn(MOD_STR, "parameter must be handle and number");
130         goto out;
131     }
132     gpio_handle.handle = duk_get_pointer(ctx, 0);
133     gpio_device        = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
134     if (NULL == gpio_device) {
135         amp_error(MOD_STR, "board_get_node_by_handle fail!");
136         goto out;
137     }
138     level = duk_get_int(ctx, 1);
139     if (level) {
140         ret = aos_hal_gpio_output_high(gpio_device);
141     } else {
142         ret = aos_hal_gpio_output_low(gpio_device);
143     }
144     if (-1 == ret) {
145         amp_error(MOD_STR, "gpio output set fail!");
146         goto out;
147     }
148     result = 0;
149 out:
150     duk_push_int(ctx, result);
151     return 1;
152 }
153 
native_gpio_read(duk_context * ctx)154 static duk_ret_t native_gpio_read(duk_context *ctx)
155 {
156     item_handle_t gpio_handle;
157     uint32_t level          = 0;
158     gpio_dev_t *gpio_device = NULL;
159 
160     if (!duk_is_pointer(ctx, 0)) {
161         amp_warn(MOD_STR, "parameter must be handle");
162         goto out;
163     }
164     gpio_handle.handle = duk_get_pointer(ctx, 0);
165     gpio_device        = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
166     if (NULL == gpio_device) {
167         amp_error(MOD_STR, "board_get_node_by_handle fail!");
168         goto out;
169     }
170     aos_hal_gpio_input_get(gpio_device, &level);
171 out:
172     duk_push_int(ctx, level);
173     return 1;
174 }
175 
176 typedef struct {
177     int js_cb_ref;
178     gpio_dev_t *dev;
179 }gpio_irq_notify_param_t;
180 
gpio_irq_notify(void * arg)181 static void gpio_irq_notify(void *arg)
182 {
183     gpio_irq_notify_param_t *param = (gpio_irq_notify_param_t *)arg;
184     duk_context *ctx = be_get_context();
185     uint32_t value = 0;
186     aos_hal_gpio_input_get(param->dev, &value);
187     be_push_ref(ctx, param->js_cb_ref);
188     duk_push_int(ctx, value);
189     if (duk_pcall(ctx, 1) != DUK_EXEC_SUCCESS) {
190         amp_console("%s", duk_safe_to_stacktrace(ctx, -1));
191     }
192     duk_pop(ctx);
193     aos_free(param);
194 }
195 
196 /* avoid stdout in irq function */
gpio_irq(void * arg)197 static void gpio_irq(void *arg)
198 {
199     static uint64_t irq_lasttime = 0;
200     uint64_t irq_nowtime = aos_now_ms();
201     gpio_dev_t *gpio = (gpio_dev_t *)arg;
202     gpio_params_t *priv = NULL;
203     gpio_irq_notify_param_t *notify;
204 
205     if (NULL == gpio) {
206         /* amp_error(MOD_STR, "param error!\n"); */
207         return;
208     }
209 
210     priv = (gpio_params_t *)gpio->priv;
211     int js_cb_ref = (int)priv->js_cb_ref;
212     if (js_cb_ref <= 0) {
213         /* amp_error(MOD_STR, "js cb ref error, ref: %d\n", js_cb_ref); */
214         return;
215     }
216 
217     if(irq_nowtime - irq_lasttime < 200){
218         // demounce in 200ms
219         return;
220     }
221     irq_lasttime = irq_nowtime;
222 
223     notify = aos_malloc(sizeof(gpio_irq_notify_param_t));
224     if (!notify)
225         return;
226 
227     notify->js_cb_ref = js_cb_ref;
228     notify->dev = gpio;
229     if (amp_task_schedule_call(gpio_irq_notify, notify) < 0) {
230         /* amp_warn(MOD_STR, "amp_task_schedule_call failed\n"); */
231     }
232 }
233 
native_gpio_on(duk_context * ctx)234 static duk_ret_t native_gpio_on(duk_context *ctx)
235 {
236     int8_t ret      = -1;
237     int8_t result   = -1;
238     int8_t irq_edge = 0;
239     item_handle_t gpio_handle;
240     gpio_handle.handle      = NULL;
241     gpio_dev_t *gpio_device = NULL;
242     gpio_params_t *priv = NULL;
243     const char *edge;
244 
245     if (!duk_is_pointer(ctx, 0) || !duk_is_function(ctx, 1)) {
246         amp_warn(MOD_STR, "parameter must be handle, string and function");
247         goto out;
248     }
249     gpio_handle.handle = duk_get_pointer(ctx, 0);
250     gpio_device        = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
251     if (NULL == gpio_device) {
252         amp_error(MOD_STR, "board_get_node_by_handle fail!");
253         goto out;
254     }
255     // edge = duk_get_string(ctx, 1);
256     // if (0 == strcmp(GPIO_IRQ_RISING_EDGE, edge)) {
257     //     irq_edge = IRQ_TRIGGER_RISING_EDGE;
258     // } else if (0 == strcmp(GPIO_IRQ_FALLING_EDGE, edge)) {
259     //     irq_edge = IRQ_TRIGGER_FALLING_EDGE;
260     // } else if (0 == strcmp(GPIO_IRQ_BOTH_EDGE, edge)) {
261     //     irq_edge = IRQ_TRIGGER_BOTH_EDGES;
262     // } else {
263     //     amp_error(MOD_STR, "irq edge wrong!");
264     //     goto out;
265     // }
266     priv = (gpio_params_t *)gpio_device->priv;
267     irq_edge = priv->irq_mode;
268     // amp_debug(MOD_STR, "%p, irq_edge:%04x port:%d", gpio_device, irq_edge, gpio_device->port);
269     ret = aos_hal_gpio_enable_irq(gpio_device, irq_edge, gpio_irq, gpio_device);
270     if (ret < 0) {
271         amp_error(MOD_STR, "aos_hal_gpio_enable_irq fail!");
272         goto out;
273     }
274     duk_dup(ctx, 1);
275     int js_cb_ref     = be_ref(ctx);
276     priv->js_cb_ref = (void *)js_cb_ref;
277     result            = 0;
278 out:
279     duk_push_int(ctx, result);
280     return 1;
281 }
282 
module_gpio_register(void)283 void module_gpio_register(void)
284 {
285     amp_debug(MOD_STR, "module_gpio_register");
286     duk_context *ctx = be_get_context();
287 
288     duk_push_object(ctx);
289 
290     AMP_ADD_FUNCTION("open",   native_gpio_open, 1);
291     AMP_ADD_FUNCTION("read",   native_gpio_read, 1);
292     AMP_ADD_FUNCTION("write",  native_gpio_write, 2);
293     AMP_ADD_FUNCTION("toggle", native_gpio_toggle, 1);
294     AMP_ADD_FUNCTION("on",     native_gpio_on, 2);
295     AMP_ADD_FUNCTION("close",  native_gpio_close, 1);
296 
297     duk_put_prop_string(ctx, -2, "GPIO");
298 }
299