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