1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  */
4 #include "di.h"
5 #include "aos/kernel.h"
6 #include "hal_iomux_haas1000.h"
7 #include "ulog/ulog.h"
8 #include <stdio.h>
9 
10 #define TAG "ex_di"
11 
12 #define TIMER_CHECK_INTERVAL 10
13 #define DI_STABLE_COUNT      5
14 
15 digital_input_value_change_notify g_di_notify_cb = NULL;
16 
17 typedef struct {
18     uint8_t         installed;
19     uint8_t         monitor_flag;
20     uint8_t         check_count;
21     gpio_pinstate_t exactly_level;
22     gpio_dev_t      gpio_dev;
23 } gpio_dev_input_t;
24 
25 /*digital input gpio dev list , the default value is high*/
26 static gpio_dev_input_t gpio_dev_input[DI_PORT_SIZE] = {
27     {0, 0, 0, GPIO_PinState_Set, {HAL_IOMUX_PIN_P2_4, IRQ_MODE, NULL} },
28     {0, 0, 0, GPIO_PinState_Set, {HAL_IOMUX_PIN_P2_5, IRQ_MODE, NULL} },
29     {0, 0, 0, GPIO_PinState_Set, {HAL_IOMUX_PIN_P4_7, IRQ_MODE, NULL} },
30     {0, 0, 0, GPIO_PinState_Set, {HAL_IOMUX_PIN_P4_6, IRQ_MODE, NULL} },
31 };
32 
33 static aos_timer_t st_di_check_timer = {0};
34 
get_di_port_by_iomux(uint8_t iomux,uint32_t * diport)35 static int32_t get_di_port_by_iomux(uint8_t iomux, uint32_t *diport)
36 {
37     uint32_t i = 0;
38 
39     for (i = 0; i < DI_PORT_SIZE; i++) {
40         if (gpio_dev_input[i].gpio_dev.port == iomux) {
41             *diport = i;
42             return 0;
43         }
44     }
45 
46     return -1;
47 }
48 
di_interrup_proc(void * arg)49 static void di_interrup_proc(void *arg)
50 {
51     uint8_t  port   = 0;
52     uint32_t diport = 0;
53     int32_t  ret    = 0;
54     uint32_t value  = 0;
55 
56     if (NULL == arg) {
57         LOGE(TAG, "Invalid input %s %d", __FILE__, __LINE__);
58         return;
59     }
60 
61     port = *(uint8_t *)arg;
62     ret  = get_di_port_by_iomux(port, &diport);
63     if (ret) {
64         LOGE(TAG, "can not porc iomux %d interrupt", port);
65         return;
66     }
67 
68     if (gpio_dev_input[diport].installed == 0) {
69         LOGE(TAG, "di port %d iomux %d haven't init yet", diport, port);
70         return;
71     }
72 
73     ret = hal_gpio_input_get(&(gpio_dev_input[diport].gpio_dev), &value);
74     if (ret) {
75         LOGE(TAG, "Fail to get di port %d input value ret %d", diport, value);
76         return;
77     }
78     hal_gpio_clear_irq(&gpio_dev_input[diport].gpio_dev);
79     hal_gpio_disable_irq(&gpio_dev_input[diport].gpio_dev);
80     if (value != gpio_dev_input[diport].exactly_level) {
81         /*add the port to the monitorlist list*/
82         // LOGI(TAG,"add di %d to monitor list", diport);
83         gpio_dev_input[diport].check_count  = 0;
84         gpio_dev_input[diport].monitor_flag = 1;
85     }
86 
87     if (value == GPIO_PinState_Set) {
88         /*rising edge interrupt, so enable falling interrupt */
89         // LOGI(TAG, "port %d recv a rising edge interrupt and enable the
90         // falling edge", diport);
91         ret = hal_gpio_enable_irq(&gpio_dev_input[diport].gpio_dev,
92                                   IRQ_TRIGGER_FALLING_EDGE, di_interrup_proc,
93                                   &gpio_dev_input[diport].gpio_dev.port);
94     }
95 
96     if (value == GPIO_PinState_Reset) {
97         /*falling edge interrupt*/
98         // LOGI(TAG, "port %d recv a falling edge interrupt and enable the
99         // rising edge", diport);
100         ret = hal_gpio_enable_irq(&gpio_dev_input[diport].gpio_dev,
101                                   IRQ_TRIGGER_RISING_EDGE, di_interrup_proc,
102                                   &gpio_dev_input[diport].gpio_dev.port);
103     }
104 
105     if (ret) {
106         LOGE(TAG, "Fail to enable gpio interrupt , gpio value is %d, ret %d",
107              value, ret);
108     }
109     return;
110 }
111 
di_value_check(void * timer,void * arg)112 static void di_value_check(void *timer, void *arg)
113 {
114     uint32_t i;
115     int32_t  ret        = 0;
116     uint32_t gpio_value = 0;
117 
118     for (i = 0; i < DI_PORT_SIZE; i++) {
119         if (gpio_dev_input[i].installed == 0 ||
120             gpio_dev_input[i].monitor_flag == 0) {
121             continue;
122         }
123         ret = hal_gpio_input_get(&gpio_dev_input[i].gpio_dev, &gpio_value);
124         if (ret) {
125             LOGE(TAG, "Fail to get di %d port %d value at %s %d", i,
126                  gpio_dev_input[i].gpio_dev.port, __FILE__, __LINE__);
127             continue;
128         }
129         if (gpio_value == gpio_dev_input[i].exactly_level) {
130             /*remove it from standout monitor list*/
131             gpio_dev_input[i].monitor_flag = 0;
132             gpio_dev_input[i].check_count  = 0;
133         } else {
134             gpio_dev_input[i].check_count++;
135             if (gpio_dev_input[i].check_count >= DI_STABLE_COUNT) {
136                 gpio_dev_input[i].monitor_flag  = 0;
137                 gpio_dev_input[i].exactly_level = gpio_value;
138                 gpio_dev_input[i].check_count   = 0;
139                 LOGI(TAG, "di %d changes to value %d", i, gpio_value);
140                 /*notify the gpio value change info */
141                 if (NULL != g_di_notify_cb) {
142                     ret = g_di_notify_cb(i, gpio_value);
143                     if (ret) {
144                         LOGE(TAG, "Fail to notify di %d value changes to %d", i,
145                              gpio_value);
146                     }
147                 }
148             }
149         }
150     }
151 }
152 
expansion_board_di_init()153 int32_t expansion_board_di_init()
154 {
155     int32_t  ret        = 0;
156     uint32_t i          = 0;
157     uint32_t gpio_value = GPIO_PinState_Set;
158 
159     /*init digital input*/
160     for (i = 0; i < DI_PORT_SIZE; i++) {
161         ret = hal_gpio_init(&gpio_dev_input[i].gpio_dev);
162         if (ret) {
163             LOGE(TAG, "di %d pin %d init fail ret", i,
164                  gpio_dev_input[i].gpio_dev.port, ret);
165             return -1;
166         }
167 
168         ret = hal_gpio_input_get(&gpio_dev_input[i].gpio_dev, &gpio_value);
169         if (ret) {
170             LOGE(TAG, "di %d pin %d fail to get value, ret %d", i,
171                  gpio_dev_input[i].gpio_dev.port, ret);
172             return -1;
173         }
174         LOGI(TAG, "di %d init value is %d", i, gpio_value);
175 
176         /*for haas1000 doesn't support both edge trigger*/
177         if (gpio_value == GPIO_PinState_Set) {
178             ret = hal_gpio_enable_irq(
179                 &gpio_dev_input[i].gpio_dev, IRQ_TRIGGER_FALLING_EDGE,
180                 di_interrup_proc, &gpio_dev_input[i].gpio_dev.port);
181         } else {
182             ret = hal_gpio_enable_irq(&gpio_dev_input[i].gpio_dev,
183                                       IRQ_TRIGGER_RISING_EDGE, di_interrup_proc,
184                                       &gpio_dev_input[i].gpio_dev.port);
185         }
186 
187         if (ret) {
188             LOGE(TAG, "di %d pin %d fail enable irq ret %d", i,
189                  gpio_dev_input[i].gpio_dev.port, ret);
190             return -1;
191         }
192         gpio_dev_input[i].installed     = 1;
193         gpio_dev_input[i].exactly_level = gpio_value;
194     }
195 
196     /*init the gpio check timer, check gpio value every 10ms */
197     ret = aos_timer_new_ext(&st_di_check_timer, di_value_check, NULL,
198                             TIMER_CHECK_INTERVAL, 1, 1);
199     if (ret) {
200         LOGE(TAG, "Fail to new gpio value check timer ret 0x%x", ret);
201         for (i = 0; i < DI_PORT_SIZE; i++) {
202             hal_gpio_disable_irq(&gpio_dev_input[i].gpio_dev);
203             hal_gpio_finalize(&gpio_dev_input[i].gpio_dev);
204             gpio_dev_input[i].installed = 0;
205         }
206         return -1;
207     }
208 
209     return 0;
210 }
211 
expansion_board_di_get_value(uint8_t port,gpio_pinstate_t * value)212 int32_t expansion_board_di_get_value(uint8_t port, gpio_pinstate_t *value)
213 {
214     int32_t ret = 0;
215 
216     if (port >= DI_PORT_SIZE || NULL == value) {
217         LOGE(TAG, " %s %d Invalid input port %d", __FILE__, __LINE__, port);
218         return -1;
219     }
220 
221     if (gpio_dev_input[port].installed == 0) {
222         LOGE(TAG, "DI port %d haven't init yet", port);
223         return -1;
224     }
225 
226     *value = gpio_dev_input[port].exactly_level;
227     return 0;
228 }
229 
expansion_board_di_change_notify_register(digital_input_value_change_notify cb)230 void expansion_board_di_change_notify_register(
231     digital_input_value_change_notify cb)
232 {
233     if (NULL == cb) {
234         LOGE(TAG, " %s %d Invalid input", __FILE__, __LINE__);
235         return;
236     }
237     g_di_notify_cb = cb;
238 }
239