1 /*
2 * Copyright (C) 2015-2019 Alibaba Group Holding Limited
3 */
4
5 #include <stdint.h>
6
7 #include "amp_config.h"
8 #include "aos_system.h"
9 #include "amp_defines.h"
10 #include "aos_hal_can.h"
11 #include "board_mgr.h"
12 #include "amp_task.h"
13 #include "be_inl.h"
14
15 #define MOD_STR "CAN"
16 #define CAN_TIMEOUT (0xFFFFFF)
17 #define MAX_CAN_RECV_LEN 8
18 #define MAX_CAN_PORT 2
19
20 typedef struct {
21 can_dev_t *can_device;
22 int js_cb_ref;
23 } can_recv_param_t;
24
25 typedef struct {
26 uint8_t buf[MAX_CAN_RECV_LEN];
27 can_frameheader_t rx_header;
28 int js_cb_ref;
29 } can_recv_notify_param_t;
30
31 static char g_can_close_flag = 0;
32 static char g_can_recv_flag = 0;
33 static aos_sem_t g_can_close_sem = NULL;
34
35 can_dev_t g_can_handle[MAX_CAN_PORT];
36
native_can_open(duk_context * ctx)37 static duk_ret_t native_can_open(duk_context *ctx)
38 {
39 int8_t ret = -1;
40 item_handle_t can_handle;
41 can_handle.handle = NULL;
42 can_dev_t *can_device = NULL;
43
44 if (!duk_is_string(ctx, 0)) {
45 amp_warn(MOD_STR, "parameter must be string");
46 goto out;
47 }
48 const char *id = duk_get_string(ctx, 0);
49 ret = board_attach_item(MODULE_CAN, id, &can_handle);
50 if (0 != ret) {
51 amp_error(MOD_STR, "board_attach_item fail!");
52 goto out;
53 }
54 amp_debug(MOD_STR, "can handle:%u", can_handle.handle);
55 can_device = board_get_node_by_handle(MODULE_CAN, &can_handle);
56 if (NULL == can_device) {
57 amp_error(MOD_STR, "board_get_node_by_handle fail!");
58 goto out;
59 }
60
61 ret = aos_hal_can_init(can_device);
62 if (0 != ret) {
63 amp_error(MOD_STR, "aos_hal_can_init fail!");
64 goto out;
65 }
66
67 g_can_handle[can_device->port] = *can_device;
68
69 out:
70 if (0 != ret) {
71 duk_push_pointer(ctx, NULL);
72 board_disattach_item(MODULE_CAN, &can_handle);
73 } else {
74 duk_push_pointer(ctx, (void *)can_handle.handle);
75 }
76 return 1;
77 }
78
native_can_close(duk_context * ctx)79 static duk_ret_t native_can_close(duk_context *ctx)
80 {
81 int8_t ret = -1;
82 item_handle_t can_handle;
83 can_dev_t *can_device = NULL;
84
85 if (!duk_is_pointer(ctx, 0)) {
86 amp_warn(MOD_STR, "parameter must be handle");
87 goto out;
88 }
89 can_handle.handle = duk_get_pointer(ctx, 0);
90 can_device = board_get_node_by_handle(MODULE_CAN, &can_handle);
91 if (NULL == can_device) {
92 amp_error(MOD_STR, "board_get_node_by_handle fail!");
93 goto out;
94 }
95 ret = aos_hal_can_finalize(can_device);
96 if (0 != ret) {
97 amp_error(MOD_STR, "aos_hal_spi_finalize fail!");
98 goto out;
99 }
100 board_disattach_item(MODULE_CAN, &can_handle);
101 g_can_close_flag = 1;
102 aos_sem_wait(&g_can_close_sem, CAN_TIMEOUT + 50);
103 g_can_close_flag = 0;
104
105 out:
106 duk_push_int(ctx, ret);
107 return 1;
108 }
109
native_can_send(duk_context * ctx)110 static duk_ret_t native_can_send(duk_context *ctx)
111 {
112 int8_t ret = -1;
113 uint8_t *data = NULL;
114 uint32_t len = 0;
115 uint32_t i = 0;
116 item_handle_t can_handle;
117 can_dev_t *can_device = NULL;
118 can_frameheader_t tx_header;
119 int arr_idx;
120 uint32_t id;
121 uint8_t rtr, dlc;
122 int err = -1;
123
124 if (!duk_is_pointer(ctx, 0) || !duk_is_object(ctx, 1) ||
125 !duk_is_array(ctx, 2)) {
126 amp_warn(MOD_STR, "parameter must be handle object array");
127 goto out;
128 }
129
130 can_handle.handle = duk_get_pointer(ctx, 0);
131 can_device = board_get_node_by_handle(MODULE_CAN, &can_handle);
132 if (NULL == can_device) {
133 amp_error(MOD_STR, "board_get_node_by_handle fail!");
134 goto out;
135 }
136
137 /* get can_frame header */
138 duk_get_prop_string(ctx, 1, "id");
139 duk_get_prop_string(ctx, 1, "rtr");
140 duk_get_prop_string(ctx, 1, "dlc");
141
142 if (!duk_is_number(ctx, -3) || !duk_is_number(ctx, -2) ||
143 !duk_is_number(ctx, -1))
144 {
145 amp_warn(MOD_STR,
146 "Parameter 1 must be an object like {id: number, rtr: number, dlc: number");
147 ret = -2;
148 goto out;
149 }
150
151 id = duk_get_uint(ctx, -3);
152 rtr = duk_get_uint(ctx, -2);
153 if (rtr > 1) {
154 amp_warn(MOD_STR, "rtr is invalid");
155 goto out;
156 }
157
158 dlc = duk_get_uint(ctx, -1);
159 if (dlc > 8) {
160 amp_warn(MOD_STR, "dlc is invalid");
161 goto out;
162 }
163
164 duk_pop_3(ctx);
165
166 tx_header.id = id;
167 tx_header.rtr = rtr;
168 tx_header.dlc = dlc;
169
170 arr_idx = duk_normalize_index(ctx, 2);
171 len = duk_get_length(ctx, arr_idx);
172 data = (uint8_t *)aos_malloc(sizeof(uint8_t) * len);
173 if (NULL == data) {
174 amp_warn(MOD_STR, "allocate memory failed");
175 goto out;
176 }
177 for (i = 0; i < len; i++) {
178 duk_get_prop_index(ctx, arr_idx, i);
179 if (!duk_is_number(ctx, -1)) {
180 amp_warn(MOD_STR, "data is not number, index: %d", i);
181 duk_pop(ctx);
182 goto out;
183 }
184 data[i] = (uint8_t)duk_get_int(ctx, -1);
185 duk_pop(ctx);
186 }
187
188 ret = aos_hal_can_send(can_device, &tx_header, data, CAN_TIMEOUT);
189 if (-1 == ret) {
190 amp_error(MOD_STR, "aos_hal_can_send fail!");
191 goto out;
192 }
193 err = 0;
194 out:
195 aos_free(data);
196 duk_push_int(ctx, err);
197 return 1;
198 }
199
can_recv_notify(void * pdata)200 static void can_recv_notify(void *pdata)
201 {
202 int i = 0;
203 can_recv_notify_param_t *p = (can_recv_notify_param_t *)pdata;
204 duk_context *ctx = be_get_context();
205
206 be_push_ref(ctx, p->js_cb_ref);
207 duk_push_uint(ctx, p->rx_header.rtr);
208 duk_push_uint(ctx, p->rx_header.id);
209 int arr_idx = duk_push_array(ctx);
210 if(p->rx_header.rtr == 0) {
211 for (i = 0; i < p->rx_header.dlc; i++) {
212 duk_push_int(ctx, p->buf[i]);
213 duk_put_prop_index(ctx, arr_idx, i);
214 }
215 }
216 if (duk_pcall(ctx, 3) != DUK_EXEC_SUCCESS) {
217 amp_console("%s", duk_safe_to_stacktrace(ctx, -1));
218 }
219
220 duk_pop(ctx);
221 duk_gc(ctx, 0);
222 // aos_free(p);
223 }
224
225 /*************************************************************************************
226 * Function: udp_recv_routine
227 * Description: create a task for blocking recvfrom call
228 * Called by:
229 **************************************************************************************/
can_recv_routine(void * arg)230 static void can_recv_routine(void *arg)
231 {
232 int ret = -1;
233 can_recv_param_t *recv_param = (can_recv_param_t *)arg;
234 can_dev_t *can_device = (can_dev_t *)recv_param->can_device;
235
236 can_recv_notify_param_t *p = aos_calloc(1, sizeof(*p));
237 if (!p) {
238 amp_warn(MOD_STR, "allocate memory failed");
239 duk_context *ctx = be_get_context();
240 be_unref(ctx, recv_param->js_cb_ref);
241 goto out;
242 }
243
244 g_can_recv_flag = 1;
245 while(1) {
246 ret = aos_hal_can_recv(can_device, &p->rx_header, p->buf, CAN_TIMEOUT);
247 if (ret == 0) {
248 p->js_cb_ref = recv_param->js_cb_ref;
249 amp_task_schedule_call(can_recv_notify, p);
250 }
251
252 if (g_can_close_flag) {
253 duk_context *ctx = be_get_context();
254 be_unref(ctx, recv_param->js_cb_ref);
255 aos_free(p);
256 break;
257 }
258
259 aos_msleep(10);
260 }
261 ret = aos_hal_can_finalize(can_device);
262 if (ret != 0) {
263 amp_error(MOD_STR, "hal can finalize failed");
264 }
265
266 out:
267 aos_free(recv_param);
268 g_can_recv_flag = 0;
269 aos_sem_signal(&g_can_close_sem);
270 aos_task_exit(0);
271
272 return;
273 }
274
native_can_receive(duk_context * ctx)275 static duk_ret_t native_can_receive(duk_context *ctx)
276 {
277 int8_t ret = -1;
278 uint8_t *data = NULL;
279 item_handle_t can_handle;
280 can_dev_t *can_device = NULL;
281 can_recv_param_t *recv_param;
282 aos_task_t can_recv_task;
283
284 if (!duk_is_pointer(ctx, 0) || !duk_is_function(ctx, 1)) {
285 amp_warn(MOD_STR, "parameter must be handle and function");
286 goto out;
287 }
288
289 can_handle.handle = duk_get_pointer(ctx, 0);
290 can_device = board_get_node_by_handle(MODULE_CAN, &can_handle);
291 if (NULL == can_device) {
292 amp_error(MOD_STR, "board_get_node_by_handle fail!");
293 goto out;
294 }
295 amp_debug(MOD_STR, "can handle %p", can_device);
296 recv_param = (can_recv_param_t *)aos_calloc(1, sizeof(*recv_param));
297 if (!recv_param) {
298 amp_warn(MOD_STR, "allocate memory failed");
299 goto out;
300 }
301
302 duk_dup(ctx, 1);
303 recv_param->js_cb_ref = be_ref(ctx);
304 recv_param->can_device = can_device;
305
306 ret = aos_task_new_ext(&can_recv_task, "amp can recv task", can_recv_routine, recv_param, 1024 * 4, ADDON_TSK_PRIORRITY);
307 if (ret != 0) {
308 amp_warn(MOD_STR, "tcp recv task error");
309 goto out;
310 }
311
312 out:
313 duk_push_int(ctx, ret);
314 return 1;
315 }
316
module_can_clean(void)317 static void module_can_clean(void)
318 {
319 if (g_can_recv_flag) {
320 g_can_close_flag = 1;
321 aos_sem_wait(&g_can_close_sem, CAN_TIMEOUT + 50);
322 g_can_close_flag = 0;
323 }
324 }
325
module_can_register(void)326 void module_can_register(void)
327 {
328 amp_debug(MOD_STR, "module_can_register");
329 duk_context *ctx = be_get_context();
330
331 if (!g_can_close_sem) {
332 if (aos_sem_new(&g_can_close_sem, 0) != 0) {
333 amp_error(MOD_STR, "create can sem fail");
334 return;
335 }
336 }
337
338 amp_module_free_register(module_can_clean);
339
340 duk_push_object(ctx);
341
342 AMP_ADD_FUNCTION("open", native_can_open, 1);
343 AMP_ADD_FUNCTION("send", native_can_send, 3);
344 AMP_ADD_FUNCTION("receive", native_can_receive, 2);
345 AMP_ADD_FUNCTION("close", native_can_close, 1);
346
347 duk_put_prop_string(ctx, -2, "CAN");
348 }
349