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 "board_mgr.h"
11 #include "be_inl.h"
12 
13 #define MOD_STR "IR"
14 
ir_learn_mode(uint32_t scl_pin,uint32_t sda_pin)15 static void ir_learn_mode(uint32_t scl_pin, uint32_t sda_pin)
16 {
17     gpio_i2c_reset(scl_pin, sda_pin);
18     gpio_i2c_delay_10us(4);
19 
20     gpio_i2c_set_low(scl_pin);
21     gpio_i2c_delay_10us(8);
22     gpio_i2c_set_high(scl_pin);
23 
24     jse_osal_delay(20);
25     gpio_i2c_start(scl_pin, sda_pin);
26     gpio_i2c_delay_10us(4);
27 
28     gpio_i2c_write_byte(scl_pin, sda_pin, 0x30);
29     gpio_i2c_delay_10us(4);
30 
31     gpio_i2c_write_byte(scl_pin, sda_pin, 0x20);
32     gpio_i2c_delay_10us(4);
33 
34     gpio_i2c_write_byte(scl_pin, sda_pin, 0x50);
35     gpio_i2c_delay_10us(8);
36 
37     gpio_i2c_stop(scl_pin, sda_pin);
38     gpio_i2c_delay_10us(4);
39 
40     gpio_i2c_reset(scl_pin, sda_pin);
41     gpio_i2c_delay_10us(4);
42 }
43 
ir_learn_read(uint32_t scl_pin,uint32_t sda_pin,uint8_t * buff)44 static int8_t ir_learn_read(uint32_t scl_pin, uint32_t sda_pin, uint8_t *buff)
45 {
46     uint8_t value    = 0;
47     uint8_t i        = 0;
48     uint8_t checksum = 0;
49     gpio_i2c_reset(scl_pin, sda_pin);
50     gpio_i2c_delay_10us(4);
51     gpio_i2c_set_low(scl_pin);
52     gpio_i2c_delay_10us(8);
53     gpio_i2c_set_high(scl_pin);
54     jse_osal_delay(20);
55 
56     gpio_i2c_start(scl_pin, sda_pin);
57     gpio_i2c_delay_10us(4);
58     gpio_i2c_write_byte(scl_pin, sda_pin, 0x30);
59     gpio_i2c_delay_10us(4);
60     gpio_i2c_write_byte(scl_pin, sda_pin, 0x62);
61     gpio_i2c_delay_10us(4);
62 
63     gpio_i2c_start(scl_pin, sda_pin);
64     gpio_i2c_delay_10us(4);
65     gpio_i2c_write_byte(scl_pin, sda_pin, 0x31);
66     gpio_i2c_delay_10us(4);
67     value = gpio_i2c_read_byte(scl_pin, sda_pin);
68     gpio_i2c_delay_10us(4);
69     if (0x00 != value) {
70         gpio_i2c_stop(scl_pin, sda_pin);
71         gpio_i2c_delay_10us(4);
72         gpio_i2c_reset(scl_pin, sda_pin);
73         gpio_i2c_delay_10us(4);
74         return -1;
75     }
76     buff[i]  = value;
77     checksum = 0xc3;
78     for (i = 1; i < 230; i++) {
79         value = gpio_i2c_read_byte(scl_pin, sda_pin);
80         gpio_i2c_delay_10us(4);
81         buff[i] = value;
82         checksum += value;
83     }
84     value = gpio_i2c_read_byte(scl_pin, sda_pin);
85     gpio_i2c_delay_10us(4);
86     gpio_i2c_stop(scl_pin, sda_pin);
87     gpio_i2c_delay_10us(4);
88     gpio_i2c_reset(scl_pin, sda_pin);
89     gpio_i2c_delay_10us(4);
90     return 0;
91 }
92 
ir_learn_start(uint32_t scl_pin,uint32_t sda_pin,uint32_t busy_bin,uint8_t buff[232])93 static int32_t ir_learn_start(uint32_t scl_pin, uint32_t sda_pin,
94                               uint32_t busy_bin, uint8_t buff[232])
95 {
96     uint8_t sumValue = 0;
97     int32_t count    = 0;
98     int8_t ret       = -1;
99     uint8_t i        = 0;
100     uint8_t tmp[512] = {0x00};
101     gpio_i2c_init(scl_pin, sda_pin);
102     gpio_i2c_set_in(busy_bin);
103     ir_learn_mode(scl_pin, sda_pin);
104     jse_osal_delay(50);
105     while (!gpio_i2c_read_pin(busy_bin)) gpio_i2c_delay_10us(10);
106     ret = ir_learn_read(scl_pin, sda_pin, tmp);
107     if (0 != ret) {
108         return -1;
109     }
110     buff[0] = 0x30;
111     sumValue += buff[0];
112     buff[1] = 0x03;
113     sumValue += buff[1];
114     for (i = 1; i < 231; i++) {
115         buff[i + 1] = tmp[i];
116         sumValue += tmp[i];
117     }
118     buff[231] = sumValue;
119     return 232;
120 }
121 
ir_counts(gpio_dev_t * gpio,uint8_t level)122 static uint32_t ir_counts(gpio_dev_t *gpio, uint8_t level)
123 {
124     int8_t ret      = 0;
125     uint32_t value  = 0;
126     uint32_t counts = 0;
127     do {
128         ret = aos_hal_gpio_input_get(gpio, &value);
129         counts += 1;
130         jse_osal_delay10us();
131     } while ((0 == ret) && (value == level));
132     return counts;
133 }
134 
ir_nec(gpio_dev_t * gpio)135 static uint32_t ir_nec(gpio_dev_t *gpio)
136 {
137     uint32_t counts = 0;
138     uint32_t value  = 0;
139     uint8_t i       = 0;
140     uint8_t j       = 0;
141     /*9ms*/
142     counts = ir_counts(gpio, 0);
143     if (counts < 850 || counts > 950) {
144         return 0;
145     }
146     /*4.5ms*/
147     counts = ir_counts(gpio, 1);
148     if (counts < 400 || counts > 500) {
149         return 0;
150     }
151     for (i = 0; i < 4; ++i) {
152         for (j = 0; j < 8; ++j) {
153             value <<= 1;
154             counts = ir_counts(gpio, 0);
155             if (counts < 30 || counts > 100) {
156                 return 0;
157             }
158             counts = ir_counts(gpio, 1);
159             if (counts > 130 && counts < 200) {
160                 value |= 1;
161             } else if (counts < 30 || counts > 100) {
162                 return 0;
163             }
164         }
165     }
166     return value;
167 }
168 
native_ir_open(duk_context * ctx)169 static duk_ret_t native_ir_open(duk_context *ctx)
170 {
171     int8_t ret = -1;
172     item_handle_t gpio_handle;
173     gpio_handle.handle      = NULL;
174     gpio_dev_t *gpio_device = NULL;
175 
176     if (!duk_is_string(ctx, 0)) {
177         amp_warn(MOD_STR, "parameter must be string");
178         goto out;
179     }
180     const char *id = duk_get_string(ctx, 0);
181     ret            = board_attach_item(MODULE_GPIO, id, &gpio_handle);
182     if (0 != ret) {
183         amp_error(MOD_STR, "board_attach_item fail!\n");
184         goto out;
185     }
186     amp_debug(MOD_STR, "ir handle:%u\n", gpio_handle.handle);
187     gpio_device = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
188     if (NULL == gpio_device) {
189         amp_error(MOD_STR, "board_get_node_by_handle fail!\n");
190         goto out;
191     }
192     ret = aos_hal_gpio_init(gpio_device);
193     if (0 != ret) {
194         amp_error(MOD_STR, "aos_hal_gpio_init fail!\n");
195         goto out;
196     }
197     gpio_device->priv = NULL;
198 out:
199     if (0 != ret) {
200         duk_push_pointer(ctx, NULL);
201         board_disattach_item(MODULE_GPIO, &gpio_handle);
202     } else {
203         duk_push_pointer(ctx, (void *)gpio_handle.handle);
204     }
205     return 1;
206 }
207 
native_ir_close(duk_context * ctx)208 static duk_ret_t native_ir_close(duk_context *ctx)
209 {
210     int8_t result = -1;
211     item_handle_t gpio_handle;
212     gpio_dev_t *gpio_device = NULL;
213 
214     if (!duk_is_pointer(ctx, 0)) {
215         amp_warn(MOD_STR, "parameter must be handle");
216         goto out;
217     }
218     gpio_handle.handle = duk_get_pointer(ctx, 0);
219     gpio_device        = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
220     if (NULL == gpio_device) {
221         amp_error(MOD_STR, "board_get_node_by_handle fail!\n");
222         goto out;
223     }
224     aos_hal_gpio_disable_irq(gpio_device);
225     gpio_device->priv = NULL;
226     board_disattach_item(MODULE_GPIO, &gpio_handle);
227     result = 0;
228 out:
229     duk_push_int(ctx, result);
230     return 1;
231 }
232 
233 struct gpio_irq_notify_param {
234     int js_cb_ref;
235     int value;
236 };
237 
gpio_irq_notify(void * arg)238 static void gpio_irq_notify(void *arg)
239 {
240     struct gpio_irq_notify_param *p = (struct gpio_irq_notify_param *)arg;
241     amp_debug(MOD_STR, "value: 0x%x\n", p->value);
242     duk_context *ctx = be_get_context();
243     be_push_ref(ctx, p->js_cb_ref);
244     duk_push_int(ctx, p->value);
245     if (duk_pcall(ctx, 1) != DUK_EXEC_SUCCESS) {
246         amp_console("%s", duk_safe_to_stacktrace(ctx, -1));
247     }
248     duk_pop(ctx);
249     aos_free(p);
250 
251     duk_gc(ctx, 0);
252 }
253 
254 /* avoid stdout in irq function */
ir_handle(void * arg)255 static void ir_handle(void *arg)
256 {
257     uint32_t value   = 0;
258     gpio_dev_t *gpio = (gpio_dev_t *)arg;
259 
260     if (NULL == gpio) {
261         /* amp_error(MOD_STR, "param error!\n"); */
262         return;
263     }
264     value = ir_nec(gpio);
265     if (0x00 == value) {
266         return;
267     }
268 
269     int js_cb_ref = (int)gpio->priv;
270     if (js_cb_ref <= 0) {
271         /* amp_error(MOD_STR, "js cb ref error, ref: %d\n", js_cb_ref); */
272         return;
273     }
274 
275     struct gpio_irq_notify_param *p =
276         (struct gpio_irq_notify_param *)aos_malloc(sizeof(*p));
277     p->js_cb_ref = js_cb_ref;
278     p->value     = value & 0xFFFF;
279     if (amp_task_schedule_call(gpio_irq_notify, p) < 0) {
280         /* amp_warn(MOD_STR, "amp_task_schedule_call failed\n"); */
281         aos_free(p);
282     }
283 }
284 
native_ir_on(duk_context * ctx)285 static duk_ret_t native_ir_on(duk_context *ctx)
286 {
287     int8_t ret = -1;
288     item_handle_t gpio_handle;
289     gpio_handle.handle      = NULL;
290     gpio_dev_t *gpio_device = NULL;
291 
292     if (!duk_is_pointer(ctx, 0) || !duk_is_function(ctx, 1)) {
293         amp_warn(MOD_STR, "parameter must be handle and function");
294         goto out;
295     }
296     gpio_handle.handle = duk_get_pointer(ctx, 0);
297     gpio_device        = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
298     if (NULL == gpio_device) {
299         amp_error(MOD_STR, "board_get_node_by_handle fail!\n");
300         goto out;
301     }
302     ret = aos_hal_gpio_enable_irq(gpio_device, IRQ_TRIGGER_FALLING_EDGE, ir_handle,
303                               gpio_device);
304     if (ret < 0) {
305         amp_error(MOD_STR, "aos_hal_gpio_enable_irq fail!\n");
306         goto out;
307     }
308     duk_dup(ctx, 1);
309     int js_cb_ref     = be_ref(ctx);
310     gpio_device->priv = (void *)js_cb_ref;
311 out:
312     duk_push_int(ctx, ret);
313     return 1;
314 }
315 
ir_delay(uint32_t counts)316 static void ir_delay(uint32_t counts)
317 {
318     uint32_t i = 0;
319     for (i = 0; i < counts; i++) jse_osal_delay10us();
320 }
321 
ir_byte(gpio_dev_t * sda,gpio_dev_t * scl,unsigned char bData)322 static void ir_byte(gpio_dev_t *sda, gpio_dev_t *scl, unsigned char bData)
323 {
324     int8_t i     = 0;
325     uint32_t val = 0;
326     aos_hal_gpio_output_low(scl);
327     ir_delay(4);
328     for (i = 7; i >= 0; i--) {
329         ir_delay(4);
330         if ((bData >> i) & 0x01) {
331             aos_hal_gpio_output_high(sda);
332         } else {
333             aos_hal_gpio_output_low(sda);
334         }
335         ir_delay(4);
336         aos_hal_gpio_output_high(scl);
337         ir_delay(4);
338         aos_hal_gpio_output_low(scl);
339     }
340     aos_hal_gpio_output_high(sda);
341     ir_delay(16);
342     aos_hal_gpio_output_high(scl);
343     ir_delay(16);
344     aos_hal_gpio_input_get(sda, &val);
345     ir_delay(16);
346     aos_hal_gpio_output_low(scl);
347     ir_delay(16);
348 }
349 
ir_buff(gpio_dev_t * sda,gpio_dev_t * scl,uint8_t * data,uint32_t count)350 static void ir_buff(gpio_dev_t *sda, gpio_dev_t *scl, uint8_t *data,
351                     uint32_t count)
352 {
353     uint32_t i = 0;
354     aos_hal_gpio_output_high(sda);
355     aos_hal_gpio_output_high(scl);
356     ir_delay(4);
357     aos_hal_gpio_output_low(scl);
358     ir_delay(8);
359     aos_hal_gpio_output_high(scl);
360     jse_osal_delay(20);
361     aos_hal_gpio_output_high(scl);
362     aos_hal_gpio_output_high(sda);
363     ir_delay(8);
364     aos_hal_gpio_output_low(sda);
365     ir_delay(40);
366     aos_hal_gpio_output_low(scl);
367     ir_delay(8);
368     ir_delay(4);
369     for (i = 0; i < count; i++) {
370         ir_byte(sda, scl, data[i]);
371         ir_delay(4);
372     }
373     ir_delay(4);
374     aos_hal_gpio_output_low(scl);
375     aos_hal_gpio_output_low(sda);
376     ir_delay(4);
377     aos_hal_gpio_output_high(scl);
378     ir_delay(4);
379     aos_hal_gpio_output_high(sda);
380     ir_delay(8);
381     aos_hal_gpio_output_low(sda);
382     aos_hal_gpio_output_low(scl);
383     ir_delay(4);
384     aos_hal_gpio_output_high(scl);
385     ir_delay(4);
386     aos_hal_gpio_output_high(sda);
387     ir_delay(8);
388 }
389 
native_ir_send(duk_context * ctx)390 static duk_ret_t native_ir_send(duk_context *ctx)
391 {
392     uint8_t *data = NULL;
393     uint32_t len  = 0;
394     uint32_t i    = 0;
395     item_handle_t gpio_handle;
396     gpio_dev_t *gpio_scl = NULL;
397     gpio_dev_t *gpio_sda = NULL;
398     int arr_idx;
399     int err = -1;
400 
401     if (!duk_is_pointer(ctx, 0) || !duk_is_pointer(ctx, 1) ||
402         !duk_is_array(ctx, 2)) {
403         amp_warn(MOD_STR, "parameter must be handle, handle and array");
404         goto out;
405     }
406 
407     gpio_handle.handle = duk_get_pointer(ctx, 0);
408     gpio_sda           = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
409     if (NULL == gpio_sda) {
410         amp_error(MOD_STR, "board_get_node_by_handle fail!\n");
411         goto out;
412     }
413 
414     gpio_handle.handle = duk_get_pointer(ctx, 1);
415     gpio_scl           = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
416     if (NULL == gpio_scl) {
417         amp_error(MOD_STR, "board_get_node_by_handle fail!\n");
418         goto out;
419     }
420 
421     arr_idx = duk_normalize_index(ctx, 2);
422     len     = duk_get_length(ctx, arr_idx);
423     data    = (uint8_t *)aos_malloc(sizeof(uint8_t) * len);
424     if (NULL == data) {
425         amp_warn(MOD_STR, "allocate memory failed");
426         goto out;
427     }
428     for (i = 0; i < len; i++) {
429         duk_get_prop_index(ctx, arr_idx, i);
430         if (!duk_is_number(ctx, -1)) {
431             amp_warn(MOD_STR, "data is not number, index: %d", i);
432             duk_pop(ctx);
433             goto out;
434         }
435         data[i] = (uint8_t)duk_get_int(ctx, -1);
436         duk_pop(ctx);
437     }
438     ir_buff(gpio_sda, gpio_scl, data, len);
439     ir_delay(10);
440     ir_buff(gpio_sda, gpio_scl, data, len);
441     ir_delay(10);
442     /* ir_buff(gpio_sda,gpio_scl,data,len); */
443     err = 0;
444 out:
445     aos_free(data);
446     duk_push_int(ctx, err);
447     return 1;
448 }
449 
native_ir_learn(duk_context * ctx)450 static duk_ret_t native_ir_learn(duk_context *ctx)
451 {
452     uint32_t i        = 0;
453     int32_t ret       = -1;
454     uint8_t buff[232] = {0x00};
455     item_handle_t gpio_handle;
456     gpio_dev_t *gpio_scl  = NULL;
457     gpio_dev_t *gpio_sda  = NULL;
458     gpio_dev_t *gpio_busy = NULL;
459 
460     if (!duk_is_pointer(ctx, 0) || !duk_is_pointer(ctx, 1) ||
461         !duk_is_pointer(ctx, 2)) {
462         amp_warn(MOD_STR, "parameter must be handle, handle and handle");
463         goto failed;
464     }
465 
466     gpio_handle.handle = duk_get_pointer(ctx, 0);
467     gpio_sda           = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
468     if (NULL == gpio_sda) {
469         amp_error(MOD_STR, "board_get_node_by_handle fail!\n");
470         goto failed;
471     }
472 
473     gpio_handle.handle = duk_get_pointer(ctx, 1);
474     gpio_scl           = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
475     if (NULL == gpio_scl) {
476         amp_error(MOD_STR, "board_get_node_by_handle fail!\n");
477         goto failed;
478     }
479 
480     gpio_handle.handle = duk_get_pointer(ctx, 2);
481     gpio_busy          = board_get_node_by_handle(MODULE_GPIO, &gpio_handle);
482     if (NULL == gpio_busy) {
483         amp_error(MOD_STR, "board_get_node_by_handle fail!\n");
484         goto failed;
485     }
486 
487     ret = ir_learn_start(gpio_scl->port, gpio_sda->port, gpio_busy->port, buff);
488     if (ret <= 0) {
489         amp_error(MOD_STR, "ir_learn_start fail!\n");
490         goto failed;
491     }
492     int arr_idx = duk_push_array(ctx);
493     for (i = 0; i < 232; ++i) {
494         duk_push_int(ctx, buff[i]);
495         duk_put_prop_index(ctx, arr_idx, i);
496     }
497     return 1;
498 
499 failed:
500     duk_push_null(ctx);
501     return 1;
502 }
503 
module_ir_register(void)504 void module_ir_register(void)
505 {
506     duk_context *ctx = be_get_context();
507 
508     duk_push_object(ctx);
509 
510     AMP_ADD_FUNCTION("open",  native_ir_open, 1);
511     AMP_ADD_FUNCTION("on",    native_ir_on, 2);
512     AMP_ADD_FUNCTION("send",  native_ir_send, 3);
513     AMP_ADD_FUNCTION("learn", native_ir_learn, 3);
514     AMP_ADD_FUNCTION("close", native_ir_close, 1);
515 
516     duk_put_prop_string(ctx, -2, "IR");
517 }
518