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