Вариант, нормально работающий на Orange Pi Zero (только GPIO на гребенке, i2c экстенд...
[gpio-int.git] / gpio-int.c
1 /* Copyright (c) 2011, RidgeRun
2  * All rights reserved.
3  *
4  * Contributors include:
5  *   Todd Fischer
6  *   Brad Lu
7  * 
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *    This product includes software developed by the RidgeRun.
18  * 4. Neither the name of the RidgeRun nor the
19  *    names of its contributors may be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  * 
22  * THIS SOFTWARE IS PROVIDED BY RIDGERUN ''AS IS'' AND ANY
23  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED. IN NO EVENT SHALL RIDGERUN BE LIABLE FOR ANY
26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <poll.h>
41 #include <getopt.h>
42 #include <time.h>
43
44  /****************************************************************
45  * Constants
46  ****************************************************************/
47  
48 #define SYSFS_GPIO_DIR "/sys/class/gpio"
49 #define POLL_TIMEOUT (3 * 1000) /* 3 seconds */
50 #define MAX_BUF 64
51
52 /****************************************************************
53  * gpio_export
54  ****************************************************************/
55 int gpio_export(unsigned int gpio)
56 {
57         int fd, len;
58         char buf[MAX_BUF];
59  
60         fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY);
61         if (fd < 0) {
62                 perror("gpio/export");
63                 return fd;
64         }
65  
66         len = snprintf(buf, sizeof(buf), "%d", gpio);
67         write(fd, buf, len);
68         close(fd);
69  
70         return 0;
71 }
72
73 /****************************************************************
74  * gpio_unexport
75  ****************************************************************/
76 int gpio_unexport(unsigned int gpio)
77 {
78         int fd, len;
79         char buf[MAX_BUF];
80  
81         fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY);
82         if (fd < 0) {
83                 perror("gpio/export");
84                 return fd;
85         }
86  
87         len = snprintf(buf, sizeof(buf), "%d", gpio);
88         write(fd, buf, len);
89         close(fd);
90         return 0;
91 }
92
93 /****************************************************************
94  * gpio_set_dir
95  ****************************************************************/
96 int gpio_set_dir(unsigned int gpio, unsigned int out_flag)
97 {
98         int fd, len;
99         char buf[MAX_BUF];
100  
101         len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR  "/gpio%d/direction", gpio);
102  
103         fd = open(buf, O_WRONLY);
104         if (fd < 0) {
105                 perror("gpio/direction");
106                 return fd;
107         }
108  
109         if (out_flag)
110                 write(fd, "out", 4);
111         else
112                 write(fd, "in", 3);
113  
114         close(fd);
115         return 0;
116 }
117
118 /****************************************************************
119  * gpio_set_value
120  ****************************************************************/
121 int gpio_set_value(unsigned int gpio, unsigned int value)
122 {
123         int fd, len;
124         char buf[MAX_BUF];
125  
126         len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
127  
128         fd = open(buf, O_WRONLY);
129         if (fd < 0) {
130                 perror("gpio/set-value");
131                 return fd;
132         }
133  
134         if (value)
135                 write(fd, "1", 2);
136         else
137                 write(fd, "0", 2);
138  
139         close(fd);
140         return 0;
141 }
142
143 /****************************************************************
144  * gpio_get_value
145  ****************************************************************/
146 int gpio_get_value(unsigned int gpio, unsigned int *value)
147 {
148         int fd, len;
149         char buf[MAX_BUF];
150         char ch;
151
152         len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
153  
154         fd = open(buf, O_RDONLY);
155         if (fd < 0) {
156                 perror("gpio/get-value");
157                 return fd;
158         }
159  
160         read(fd, &ch, 1);
161
162         if (ch != '0') {
163                 *value = 1;
164         } else {
165                 *value = 0;
166         }
167  
168         close(fd);
169         return 0;
170 }
171
172
173 /****************************************************************
174  * gpio_set_edge
175  ****************************************************************/
176
177 int gpio_set_edge(unsigned int gpio, char *edge)
178 {
179         int fd, len;
180         char buf[MAX_BUF];
181
182         len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio);
183  
184         fd = open(buf, O_WRONLY);
185         if (fd < 0) {
186                 perror("gpio/set-edge");
187                 return fd;
188         }
189  
190         write(fd, edge, strlen(edge) + 1); 
191         close(fd);
192         return 0;
193 }
194
195 int gpio_set_level(unsigned int gpio, int level)
196 {
197         int fd, len;
198         char buf[MAX_BUF];
199
200         len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/active_low", gpio);
201  
202         fd = open(buf, O_WRONLY);
203         if (fd < 0) {
204                 perror("gpio/set-level");
205                 return fd;
206         }
207  
208         write(fd, level?"1":"0", 2); 
209
210         close(fd);
211         return 0;
212 }
213
214 /****************************************************************
215  * gpio_fd_open
216  ****************************************************************/
217
218 int gpio_fd_open(unsigned int gpio)
219 {
220         int fd, len;
221         char buf[MAX_BUF];
222
223         len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
224  
225         fd = open(buf, O_RDONLY | O_NONBLOCK );
226         if (fd < 0) {
227                 perror("gpio/fd_open");
228         }
229         return fd;
230 }
231
232 /****************************************************************
233  * gpio_fd_close
234  ****************************************************************/
235
236 int gpio_fd_close(int fd)
237 {
238         return close(fd);
239 }
240
241 /****************************************************************
242  * Main
243  ****************************************************************/
244
245 #define OPTSTRING "e:l:"
246
247 int main(int argc, char **argv, char **envp)
248 {
249         struct pollfd *fdset;
250         int timeout, rc;
251         char *buf[MAX_BUF];
252         unsigned int gpio;
253         unsigned int count;
254         unsigned int *gpios;
255         int len;
256         int i,j;
257         char valbuf;
258         int default_level=1;
259         char *default_edge="both";
260         struct timespec spec;
261         int s,ms;
262
263         int ch;
264
265         while (-1 != (ch = getopt(argc, argv, OPTSTRING))) {
266                 switch (ch) {
267                         case 'e':
268                                 default_edge=strdup(optarg);
269                                 if ( ! ((0 == strncmp(default_edge,"rising",8)) ||
270                                      (0 == strncmp(default_edge,"falling",8)) ||
271                                      (0 == strncmp(default_edge,"both",8)))
272                                    )
273                                 {
274                                         fprintf(stderr, "error: invalid edge value: %s\n", optarg);
275                                         exit(1);
276                                 }
277                                 break;
278                         case 'l':
279                                 if ( 0 == strncmp(optarg,"low",8) ) {
280                                         default_level=1;
281                                 } else if ( 0 == strncmp(optarg,"high",8) ) {
282                                         default_level=0;
283                                 } else {
284                                         fprintf(stderr, "error: invalid level value: %s\n", optarg);
285                                         exit(1);
286                                 }
287                                 break;
288                         case '?':
289                                 printf("Usage: gpio-int [-l level] [-e edge ] <gpio-pin...>\n\n");
290                                 printf("Waits for a change in the GPIO pins voltage level\n");
291                                 exit(2);
292                 }
293         }
294
295         count=argc-optind;
296
297         gpios = malloc(count*sizeof(unsigned int));
298         fdset = malloc(count*sizeof(fdset[0]));
299
300         j=0;
301         for (i=optind;i<argc;i++) {
302                 gpio = atoi(argv[i]);
303                 gpio_unexport(gpio);
304                 gpio_export(gpio);
305                 gpio_set_dir(gpio, 0);
306                 gpio_set_edge(gpio, default_edge);
307                 gpio_set_level(gpio, default_level);
308                 fdset[j].fd = gpio_fd_open(gpio);
309                 fdset[j].events = POLLPRI;
310                 gpios[j] = gpio;
311                 j++;
312         }
313
314         timeout = POLL_TIMEOUT;
315  
316         while (1) {
317
318                 rc = poll(fdset, count, timeout);      
319
320                 if (rc < 0) {
321                         printf("\npoll() failed!\n");
322                         break;
323                 }
324       
325                 clock_gettime(CLOCK_REALTIME, &spec);
326                 for (i=0;i<count;i++) {
327                         if (fdset[i].revents & POLLPRI) {
328                                 lseek(fdset[i].fd, 0, SEEK_SET);
329                                 len = read(fdset[i].fd, buf, MAX_BUF);
330                                 valbuf = buf[0];
331                                 s=spec.tv_sec;
332                                 ms = spec.tv_nsec / 1.0e6;
333                                 printf("%d %c %d.%03d\n", gpios[i], valbuf, s, ms);
334                         }
335                 }
336
337                 fflush(stdout);
338         }
339
340         for (i=0;i<count;i++) {
341                 gpio_fd_close(fdset[i].fd);
342         }
343         return 0;