90c2a21c83bf636ce65b22245ee34348feb8bbfa
[platform/core/api/peripheral-io.git] / src / interface / peripheral_interface_gpio.c
1 /*
2  * Copyright (c) 2016-2017 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <poll.h>
18 #include "peripheral_interface_gpio.h"
19
20 #define GPIO_INTERRUPTED_CALLBACK_UNSET 0
21 #define GPIO_INTERRUPTED_CALLBACK_SET   1
22
23 int peripheral_interface_gpio_set_initial_direction_into_handle(peripheral_gpio_h gpio)
24 {
25         static predefined_type_s types[2] = {
26                 {"in",   2},
27                 {"out",  3},
28         };
29
30         int index;
31         char gpio_buf[GPIO_BUFFER_MAX] = {0, };
32
33         int ret = read(gpio->fd_direction, &gpio_buf, GPIO_BUFFER_MAX);
34         CHECK_ERROR(ret <= 0);
35
36         for (index = 0; index < 2; index++) {
37                 if (!strncmp(gpio_buf, types[index].type, types[index].len)) {
38                         // PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_HIGH and PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW : out type
39                         gpio->direction = (peripheral_gpio_direction_e)index;
40                         return PERIPHERAL_ERROR_NONE;
41                 }
42         }
43
44         return PERIPHERAL_ERROR_IO_ERROR;
45 }
46
47 /*
48  *      [edge_mode]                [direction]
49  *
50  *          none -----------------> in, out (O)
51  *
52  * rising, falling, both ---------> in (O)
53  *                          \
54  *                           -----> out (X)
55  */
56 int peripheral_interface_gpio_set_direction(peripheral_gpio_h gpio, peripheral_gpio_direction_e direction)
57 {
58         RETV_IF(gpio->direction == direction, PERIPHERAL_ERROR_NONE);
59         RETV_IF(gpio->edge != PERIPHERAL_GPIO_EDGE_NONE, PERIPHERAL_ERROR_IO_ERROR);
60
61         static predefined_type_s types[3] = {
62                 {"in",   2},
63                 {"high", 4},
64                 {"low",  3}
65         };
66
67         int ret = write(gpio->fd_direction, types[direction].type, types[direction].len);
68         CHECK_ERROR(ret != types[direction].len);
69
70         gpio->direction = direction;
71
72         return PERIPHERAL_ERROR_NONE;
73 }
74
75 int peripheral_interface_gpio_set_initial_edge_into_handle(peripheral_gpio_h gpio)
76 {
77         static predefined_type_s types[4] = {
78                 {"none",    4},
79                 {"rising",  6},
80                 {"falling", 7},
81                 {"both",    4}
82         };
83
84         int index;
85         char gpio_buf[GPIO_BUFFER_MAX] = {0, };
86
87         int ret = read(gpio->fd_edge, &gpio_buf, GPIO_BUFFER_MAX);
88         CHECK_ERROR(ret <= 0);
89
90         for (index = 0; index < 4; index++) {
91                 if (!strncmp(gpio_buf, types[index].type, types[index].len)) {
92                         gpio->edge = (peripheral_gpio_edge_e)index;
93                         return PERIPHERAL_ERROR_NONE;
94                 }
95         }
96
97         return PERIPHERAL_ERROR_IO_ERROR;
98 }
99
100 /*
101  * [direction]          [edge_mode]
102  *
103  *    in ---------> none, rising, falling, both (O)
104  *
105  *    out --------> none (O)
106  *          \
107  *           -----> rising, falling, both (X)
108  */
109 int peripheral_interface_gpio_set_edge_mode(peripheral_gpio_h gpio, peripheral_gpio_edge_e edge)
110 {
111         RETV_IF(gpio->edge == edge, PERIPHERAL_ERROR_NONE);
112         RETV_IF(gpio->direction != PERIPHERAL_GPIO_DIRECTION_IN, PERIPHERAL_ERROR_IO_ERROR);
113
114         static predefined_type_s types[4] = {
115                 {"none",    4},
116                 {"rising",  6},
117                 {"falling", 7},
118                 {"both",    4}
119         };
120
121         int ret = write(gpio->fd_edge, types[edge].type, types[edge].len);
122         CHECK_ERROR(ret != types[edge].len);
123
124         gpio->edge = edge;
125
126         return PERIPHERAL_ERROR_NONE;
127 }
128
129 /*
130  * [direction]     [value]
131  *
132  *    in ---------> write (X)
133  *    out --------> write (O)
134  */
135 int peripheral_interface_gpio_write(peripheral_gpio_h gpio, uint32_t value)
136 {
137         RETV_IF(gpio->direction == PERIPHERAL_GPIO_DIRECTION_IN, PERIPHERAL_ERROR_IO_ERROR);
138
139         static predefined_type_s types[2] = {
140                 {"0", 1},
141                 {"1", 1}
142         };
143
144         int ret = write(gpio->fd_value, types[value].type, types[value].len);
145         CHECK_ERROR(ret != types[value].len);
146
147         return PERIPHERAL_ERROR_NONE;
148 }
149
150 /*
151  * [direction]     [value]
152  *
153  *    in ---------> read (O)
154  *    out --------> read (O)
155  */
156 int peripheral_interface_gpio_read(peripheral_gpio_h gpio, uint32_t *value)
157 {
158         int ret;
159         int length = 1;
160         char gpio_buf[GPIO_BUFFER_MAX] = {0, };
161
162         lseek(gpio->fd_value, 0, SEEK_SET);
163         ret = read(gpio->fd_value, &gpio_buf, length);
164         CHECK_ERROR(ret != length);
165
166         if (gpio_buf[0] == '0') {
167                 *value = 0;
168         } else if (gpio_buf[0] == '1') {
169                 *value = 1;
170         } else {
171                 _E("Error: gpio value is error \n");
172                 return PERIPHERAL_ERROR_IO_ERROR;
173         }
174
175         return PERIPHERAL_ERROR_NONE;
176 }
177
178 void peripheral_interface_gpio_close(peripheral_gpio_h gpio)
179 {
180         peripheral_interface_gpio_unset_interrupted_cb(gpio);
181
182         close(gpio->fd_direction);
183         close(gpio->fd_edge);
184         close(gpio->fd_value);
185 }
186
187 static gboolean __peripheral_interface_gpio_interrupted_cb_invoke(gpointer data)
188 {
189         peripheral_gpio_h gpio = (peripheral_gpio_h)data;
190         gpio->cb_info.cb(gpio, gpio->cb_info.error, NULL);
191         return FALSE;
192 }
193
194 static gpointer __peripheral_interface_gpio_poll(void *data)
195 {
196         peripheral_gpio_h gpio = (peripheral_gpio_h)data;
197
198         int ret;
199         int poll_state = 0;
200         struct pollfd poll_fd;
201
202         poll_fd.fd = gpio->fd_value;
203         poll_fd.events = POLLPRI;
204
205         uint32_t value;
206
207         while (g_atomic_int_get(&gpio->cb_info.status) == GPIO_INTERRUPTED_CALLBACK_SET) {
208
209                 poll_state = poll(&poll_fd, 1, 3000);
210
211                 if (poll_state == 0)
212                         continue;
213
214                 if (poll_state < 0) {
215                         _E("poll failed!");
216                         gpio->cb_info.error = PERIPHERAL_ERROR_IO_ERROR;
217                         g_idle_add_full(G_PRIORITY_HIGH_IDLE, __peripheral_interface_gpio_interrupted_cb_invoke, gpio, NULL);
218                         break;
219                 }
220
221                 if (poll_fd.revents & POLLPRI) {
222                         ret = peripheral_interface_gpio_read(gpio, &value);
223                         if (ret != PERIPHERAL_ERROR_NONE)
224                                 continue;
225                 } else {
226                         continue;
227                 }
228
229                 if (gpio->edge == PERIPHERAL_GPIO_EDGE_NONE)
230                         continue;
231
232                 if (gpio->edge == PERIPHERAL_GPIO_EDGE_RISING && value == 0)
233                         continue;
234
235                 if (gpio->edge == PERIPHERAL_GPIO_EDGE_FALLING && value == 1)
236                         continue;
237
238                 gpio->cb_info.error = PERIPHERAL_ERROR_NONE;
239                 g_idle_add_full(G_PRIORITY_HIGH_IDLE, __peripheral_interface_gpio_interrupted_cb_invoke, gpio, NULL);
240         }
241
242         return NULL;
243 }
244
245 int peripheral_interface_gpio_set_interrupted_cb(peripheral_gpio_h gpio, peripheral_gpio_interrupted_cb callback, void *user_data)
246 {
247         RETV_IF(gpio->direction != PERIPHERAL_GPIO_DIRECTION_IN, PERIPHERAL_ERROR_IO_ERROR);
248
249         peripheral_interface_gpio_unset_interrupted_cb(gpio);
250
251         gpio->cb_info.cb = callback;
252         gpio->cb_info.user_data = user_data;
253         g_atomic_int_set(&gpio->cb_info.status, GPIO_INTERRUPTED_CALLBACK_SET);
254         gpio->cb_info.thread = g_thread_new(NULL, __peripheral_interface_gpio_poll, gpio);
255
256         return PERIPHERAL_ERROR_NONE;
257 }
258
259 int peripheral_interface_gpio_unset_interrupted_cb(peripheral_gpio_h gpio)
260 {
261         g_atomic_int_set(&gpio->cb_info.status, GPIO_INTERRUPTED_CALLBACK_UNSET);
262
263         if (gpio->cb_info.thread != NULL) {
264                 g_thread_join(gpio->cb_info.thread);
265                 gpio->cb_info.thread = NULL;
266         }
267
268         return PERIPHERAL_ERROR_NONE;
269 }