gpio  1.4.2
General Purpose I/O Package
gpio.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: gpio
4 //
5 // Library: libgpio
6 //
7 // File: gpio.c
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2015-04-09 15:03:13 -0600 (Thu, 09 Apr 2015) $
12  * $Rev: 3916 $
13  *
14  * \brief GPIO library definitions using the /sys/class/gpio interface.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  *
18  * \copyright
19  * \h_copy 2015-2017. RoadNarrows LLC.\n
20  * http://www.roadnarrows.com\n
21  * All Rights Reserved
22  */
23 /*
24  * @EulaBegin@
25 // Permission is hereby granted, without written agreement and without
26 // license or royalty fees, to use, copy, modify, and distribute this
27 // software and its documentation for any purpose, provided that
28 // (1) The above copyright notice and the following two paragraphs
29 // appear in all copies of the source code and (2) redistributions
30 // including binaries reproduces these notices in the supporting
31 // documentation. Substantial modifications to this software may be
32 // copyrighted by their authors and need not follow the licensing terms
33 // described here, provided that the new terms are clearly indicated in
34 // all files where they apply.
35 //
36 // IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
37 // OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
38 // PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
39 // DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
40 // EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
41 // THE POSSIBILITY OF SUCH DAMAGE.
42 //
43 // THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
44 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
45 // FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
46 // "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
47 // PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
48  * @EulaEnd@
49  */
50 //
51 ////////////////////////////////////////////////////////////////////////////////
52 
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <sys/time.h>
56 #include <sys/select.h>
57 
58 #include <fcntl.h>
59 #include <unistd.h>
60 #include <stdio.h>
61 #include <errno.h>
62 #include <string.h>
63 
64 #include "rnr/rnrconfig.h"
65 #include "rnr/log.h"
66 
67 #include "rnr/gpio.h"
68 
69 
70 // ---------------------------------------------------------------------------
71 // Private Interface
72 // ---------------------------------------------------------------------------
73 
74 static const char *GpioRoot = "/sys/class/gpio";
75 
76 /*!
77  * \brief Read GPIO current direction.
78  *
79  * Method: sysfs
80  *
81  * \param gpio The sysfs exported GPIO number.
82  *
83  * \return
84  * On success GPIO_DIR_IN(0) or GPIO_DIR_OUT(1) is returned.\n
85  * Otherwise RC_ERROR(-1) is returned.
86  */
87 static int gpioReadDirection(int gpio)
88 {
89  int fd;
90  char buf[MAX_PATH];
91  ssize_t n;
92 
93  sprintf(buf, "%s/gpio%d/direction", GpioRoot, gpio);
94 
95  if( (fd = open(buf, O_RDONLY)) < 0 )
96  {
97  LOGSYSERROR("open(\"%s\", O_WRONLY)", buf);
98  return RC_ERROR;
99  }
100 
101  if( (n = read(fd, buf, sizeof(buf))) < 0 )
102  {
103  LOGSYSERROR("read(%d, %p, %zu)", fd, buf, sizeof(buf));
104  close(fd);
105  return RC_ERROR;
106  }
107 
108  close(fd);
109 
110  buf[n] = 0;
111 
112  if( !strncmp(buf, GPIO_DIR_IN_STR, strlen(GPIO_DIR_IN_STR)) )
113  {
114  return GPIO_DIR_IN;
115  }
116  else if( !strncmp(buf, GPIO_DIR_OUT_STR, strlen(GPIO_DIR_OUT_STR)) )
117  {
118  return GPIO_DIR_OUT;
119  }
120  else
121  {
122  LOGERROR("Unknown direction value: \"%s\".", buf);
123  return RC_ERROR;
124  }
125 }
126 
127 /*!
128  * \brief Read GPIO current edge trigger.
129  *
130  * Method: sysfs
131  *
132  * \param gpio The sysfs exported GPIO number.
133  *
134  * \return
135  * On success GPIO_EDGE_NONE(0), GPIO_EDGE_RISING(1),
136  * GPIO_EDGE_FALLING(2), or GPIO_EDGE_BOTH(3) is returned.\n
137  * Otherwise RC_ERROR(-1) is returned.
138  */
139 static int gpioReadEdge(int gpio)
140 {
141  int fd;
142  char buf[MAX_PATH];
143  ssize_t n;
144 
145  sprintf(buf, "%s/gpio%d/edge", GpioRoot, gpio);
146 
147  if( (fd = open(buf, O_RDONLY)) < 0 )
148  {
149  LOGSYSERROR("open(\"%s\", O_WRONLY)", buf);
150  return RC_ERROR;
151  }
152 
153  if( (n = read(fd, buf, sizeof(buf))) < 0 )
154  {
155  LOGSYSERROR("read(%d, %p, %zu)", fd, buf, sizeof(buf));
156  close(fd);
157  return RC_ERROR;
158  }
159 
160  close(fd);
161 
162  buf[n] = 0;
163 
164  if( !strncmp(buf, GPIO_EDGE_NONE_STR, strlen(GPIO_EDGE_NONE_STR)) )
165  {
166  return GPIO_EDGE_NONE;
167  }
168  else if( !strncmp(buf, GPIO_EDGE_RISING_STR, strlen(GPIO_EDGE_RISING_STR)) )
169  {
170  return GPIO_EDGE_RISING;
171  }
172  else if( !strncmp(buf, GPIO_EDGE_FALLING_STR, strlen(GPIO_EDGE_FALLING_STR)) )
173  {
174  return GPIO_EDGE_FALLING;
175  }
176  else if( !strncmp(buf, GPIO_EDGE_BOTH_STR, strlen(GPIO_EDGE_BOTH_STR)) )
177  {
178  return GPIO_EDGE_BOTH;
179  }
180  else
181  {
182  LOGERROR("Unknown edge value: \"%s\".", buf);
183  return RC_ERROR;
184  }
185 }
186 
187 
188 // ---------------------------------------------------------------------------
189 // Public Interface
190 // ---------------------------------------------------------------------------
191 
192 int gpioExport(int gpio)
193 {
194  int fd;
195  char buf[MAX_PATH];
196 
197  sprintf(buf, "%s/export", GpioRoot);
198 
199  if( (fd = open(buf, O_WRONLY)) < 0 )
200  {
201  LOGSYSERROR("open(\"%s\", O_WRONLY)", buf);
202  return RC_ERROR;
203  }
204 
205  sprintf(buf, "%d", gpio);
206 
207  if( write(fd, buf, strlen(buf)) < 0 )
208  {
209  LOGSYSERROR("write(%d, \"%s\", %zu)", fd, buf, strlen(buf));
210  close(fd);
211  return RC_ERROR;
212  }
213 
214  close(fd);
215 
216  LOGDIAG3("Exported GPIO %d interface.", gpio);
217 
218  return OK;
219 }
220 
221 int gpioUnexport(int gpio)
222 {
223  int fd;
224  char buf[MAX_PATH];
225 
226  sprintf(buf, "%s/unexport", GpioRoot);
227 
228  if( (fd = open(buf, O_WRONLY)) < 0 )
229  {
230  LOGSYSERROR("open(\"%s\", O_WRONLY)", buf);
231  return RC_ERROR;
232  }
233 
234  sprintf(buf, "%d", gpio);
235 
236  if( write(fd, buf, strlen(buf)) < 0 )
237  {
238  LOGSYSERROR("write(%d, \"%s\", %zu)", fd, buf, strlen(buf));
239  close(fd);
240  return RC_ERROR;
241  }
242 
243  close(fd);
244 
245  LOGDIAG3("Unexported GPIO %d interface.", gpio);
246 
247  return OK;
248 }
249 
250 int gpioSetDirection(int gpio, int dir)
251 {
252  int fd;
253  char buf[MAX_PATH];
254  const char *sDir;
255 
256  switch( dir )
257  {
258  case GPIO_DIR_IN:
259  sDir = GPIO_DIR_IN_STR;
260  break;
261  case GPIO_DIR_OUT:
262  sDir = GPIO_DIR_OUT_STR;
263  break;
264  default:
265  LOGERROR("GPIO %d: \"%s\": Invalid direction. Must be one of: %d %d.",
266  gpio, dir, GPIO_DIR_IN, GPIO_DIR_OUT);
267  return RC_ERROR;
268  }
269 
270  sprintf(buf, "%s/gpio%d/direction", GpioRoot, gpio);
271 
272  if( (fd = open(buf, O_WRONLY)) < 0 )
273  {
274  LOGSYSERROR("open(\"%s\", O_WRONLY)", buf);
275  return RC_ERROR;
276  }
277 
278  if( write(fd, sDir, strlen(sDir)) < 0 )
279  {
280  LOGSYSERROR("write(%d, \"%s\", %zu)", fd, sDir, strlen(sDir));
281  close(fd);
282  return RC_ERROR;
283  }
284 
285  close(fd);
286 
287  LOGDIAG3("GPIO %d direction set to %s.", gpio, sDir);
288 
289  return OK;
290 }
291 
292 int gpioSetEdge(int gpio, int edge)
293 {
294  int fd;
295  char buf[MAX_PATH];
296  const char *sEdge;
297 
298  switch( edge )
299  {
300  case GPIO_EDGE_NONE:
301  sEdge = GPIO_EDGE_NONE_STR;
302  break;
303  case GPIO_EDGE_RISING:
304  sEdge = GPIO_EDGE_RISING_STR;
305  break;
306  case GPIO_EDGE_FALLING:
307  sEdge = GPIO_EDGE_FALLING_STR;
308  break;
309  case GPIO_EDGE_BOTH:
310  sEdge = GPIO_EDGE_BOTH_STR;
311  break;
312  default:
313  LOGERROR("GPIO %d: \"%s\": Invalid edge. Must be in range [%d-%d].",
314  gpio, edge, GPIO_EDGE_NONE, GPIO_EDGE_BOTH);
315  return RC_ERROR;
316  }
317 
318  sprintf(buf, "%s/gpio%d/edge", GpioRoot, gpio);
319 
320  if( (fd = open(buf, O_WRONLY)) < 0 )
321  {
322  LOGSYSERROR("open(\"%s\", O_WRONLY)", buf);
323  return RC_ERROR;
324  }
325 
326  if( write(fd, sEdge, strlen(sEdge)) < 0 )
327  {
328  LOGSYSERROR("write(%d, \"%s\", %zu)", fd, sEdge, strlen(sEdge));
329  close(fd);
330  return RC_ERROR;
331  }
332 
333  close(fd);
334 
335  LOGDIAG3("GPIO %d edge set to %s.", gpio, sEdge);
336 
337  return OK;
338 }
339 
340 int gpioSetPull(int gpio, int pull)
341 {
342  LOGERROR("Sysfs GPIO pull operation not supported.");
343  return RC_ERROR;
344 }
345 
346 int gpioProbe(int gpio, gpio_info_t *p)
347 {
348  int v;
349  int rc = OK;
350 
351  p->gpio = gpio;
352  p->pin = -1; // gpioExportedToPin(gpio);
353  p->dir = GPIO_DIR_IN;
354  p->edge = GPIO_EDGE_NONE;
355  p->pull = GPIO_PULL_DS;
356  p->value = 0;
357 
358  if( (v = gpioReadDirection(gpio)) < 0 )
359  {
360  rc = RC_ERROR;
361  }
362  else
363  {
364  p->dir = v;
365  }
366 
367  if( (v = gpioReadEdge(gpio)) < 0 )
368  {
369  rc = RC_ERROR;
370  }
371  else
372  {
373  p->edge = v;
374  }
375 
376  if( (v = gpioRead(gpio)) < 0 )
377  {
378  rc = RC_ERROR;
379  }
380  else
381  {
382  p->value = v;
383  }
384 
385  return rc;
386 }
387 
388 int gpioRead(int gpio)
389 {
390  int fd;
391  char buf[MAX_PATH];
392  char c;
393 
394  sprintf(buf, "%s/gpio%d/value", GpioRoot, gpio);
395 
396  if( (fd = open(buf, O_RDONLY)) < 0 )
397  {
398  LOGSYSERROR("open(\"%s\", O_RDONLY)", buf);
399  return RC_ERROR;
400  }
401 
402  if( read(fd, &c, 1) < 0 )
403  {
404  LOGSYSERROR("read(%s, ...)", fd);
405  close(fd);
406  return RC_ERROR;
407  }
408 
409  LOGDIAG3("Read GPIO %d value %c.", gpio, c);
410 
411  return c == '0'? 0: 1;
412 }
413 
414 int gpioWrite(int gpio, int value)
415 {
416  int fd;
417  char buf[MAX_PATH];
418  char c;
419 
420  sprintf(buf, "%s/gpio%d/value", GpioRoot, gpio);
421 
422  if( (fd = open(buf, O_WRONLY)) < 0 )
423  {
424  LOGSYSERROR("open(\"%s\", O_WRONLY)", buf);
425  return RC_ERROR;
426  }
427 
428  c = value == 0? '0': '1';
429 
430  if( write(fd, &c, 1) < 0 )
431  {
432  LOGSYSERROR("write(%s, \"%c\", 1)", fd, c);
433  close(fd);
434  return RC_ERROR;
435  }
436 
437  LOGDIAG3("Wrote GPIO %d value %c.", gpio, c);
438 
439  return OK;
440 }
441 
442 int gpioNotify(int fd, double timeout)
443 {
444  fd_set efds;
445  struct timeval tv;
446  int rc;
447 
448  FD_ZERO(&efds);
449  FD_SET(fd, &efds);
450 
451  // no timeout
452  if( timeout <= 0.0 )
453  {
454  rc = select(fd+1, NULL, NULL, &efds, NULL);
455  }
456  else
457  {
458  tv.tv_sec = (long)timeout;
459  tv.tv_usec = (long)((timeout - (double)tv.tv_sec) * 1000000.0);
460  if( tv.tv_usec > 1000000 )
461  {
462  ++tv.tv_sec;
463  tv.tv_usec = 0;
464  }
465  //fprintf(stderr, "%lf --> %ld %ld\n", timeout, tv.tv_sec, tv.tv_usec);
466  rc = select(fd+1, NULL, NULL, &efds, &tv);
467  }
468 
469  // change
470  if( rc > 0 )
471  {
472  LOGDIAG3("GPIO value changed.");
473  rc = gpioQuickRead(fd);
474  }
475 
476  // timeout
477  else if( rc == 0 )
478  {
479  LOGDIAG3("GPIO watch timedout.");
480  rc = gpioQuickRead(fd);
481  }
482 
483  // error
484  else
485  {
486  LOGSYSERROR("select(%d, ...)", fd);
487  }
488 
489  return rc;
490 }
491 
492 int gpioOpen(int gpio)
493 {
494  int fd;
495  char buf[MAX_PATH];
496 
497  sprintf(buf, "%s/gpio%d/value", GpioRoot, gpio);
498 
499  if( (fd = open(buf, O_RDWR)) < 0 )
500  {
501  LOGSYSERROR("open(\"%s\", O_RDWR)", buf);
502  return RC_ERROR;
503  }
504 
505  LOGDIAG3("Opened GPIO %d.", gpio);
506 
507  return fd;
508 }
509 
510 int gpioClose(int fd)
511 {
512  if( fd >= 0 )
513  {
514  close(fd);
515  }
516 
517  return OK;
518 }
519 
520 int gpioQuickRead(int fd)
521 {
522  char c;
523 
524  // go to top of 'file'
525  lseek(fd, 0, SEEK_SET);
526 
527  if( read(fd, &c, 1) < 0 )
528  {
529  LOGSYSERROR("read(%s, ...)", fd);
530  return RC_ERROR;
531  }
532 
533  LOGDIAG3("Read GPIO value %c.", c);
534 
535  return c == '0'? 0: 1;
536 }
537 
538 int gpioQuickWrite(int fd, int value)
539 {
540  char c;
541 
542  // go to top of 'file'
543  lseek(fd, 0, SEEK_SET);
544 
545  c = value == 0? '0': '1';
546 
547  if( write(fd, &c, 1) < 0 )
548  {
549  LOGSYSERROR("write(%s, \"%c\", 1)", fd, c);
550  return RC_ERROR;
551  }
552 
553  LOGDIAG3("Wrote GPIO value %c.", c);
554 
555  return OK;
556 }
557 
558 int gpioBitBang(int fd,
559  byte_t pattern[],
560  size_t bitCount,
561  unsigned int usecIbd)
562 {
563  size_t byteCount = (bitCount + 7) / 8;
564  size_t i, j, k;
565  int mask, value;
566 
567  for(i=0, k=0; i<byteCount; ++i)
568  {
569  for(j=0, mask=0x80; j<8 && k<bitCount; ++j, ++k)
570  {
571  if( usecIbd > 0 )
572  {
573  usleep(usecIbd);
574  }
575  value = pattern[i] & mask? 1: 0;
576  mask >>= 1;
577  if( gpioQuickWrite(fd, value) < 0 )
578  {
579  return RC_ERROR;
580  }
581  }
582  }
583 
584  return OK;
585 }
586 
587 void gpioMakeDirname(int gpio, char buf[], size_t size)
588 {
589  snprintf(buf, size, "%s/gpio%d", GpioRoot, gpio);
590  buf[size-1] = 0;
591 }
#define GPIO_EDGE_FALLING
falling edge
Definition: gpio.h:78
int gpioClose(int fd)
Close GPIO pin.
Definition: gpio.c:510
int gpioExport(int gpio)
Export (create) a GPIO interface.
Definition: gpio.c:192
int pull
pull state
Definition: gpio.h:104
#define GPIO_PULL_DS
disable pullup/down
Definition: gpio.h:88
int gpioSetDirection(int gpio, int dir)
Set GPIO signal direction.
Definition: gpio.c:250
int gpio
sysfs exported gpio number
Definition: gpio.h:100
GPIO interface declarations and defines.
#define GPIO_EDGE_BOTH
both edges
Definition: gpio.h:79
#define GPIO_EDGE_FALLING_STR
falling edge string
Definition: gpio.h:82
#define GPIO_DIR_IN
input
Definition: gpio.h:68
static int gpioReadDirection(int gpio)
Read GPIO current direction.
Definition: gpio.c:87
int gpioSetPull(int gpio, int pull)
Set GPIO pull.
Definition: gpio.c:340
static int gpioReadEdge(int gpio)
Read GPIO current edge trigger.
Definition: gpio.c:139
#define GPIO_DIR_OUT_STR
output string
Definition: gpio.h:71
int edge
gpio edge type trigger
Definition: gpio.h:103
int gpioRead(int gpio)
Read GPIO pin&#39;s current value.
Definition: gpio.c:388
int gpioWrite(int gpio, int value)
Write GPIO value.
Definition: gpio.c:414
int gpioQuickWrite(int fd, int value)
Quick write GPIO pin value.
Definition: gpio.c:538
#define GPIO_EDGE_BOTH_STR
both edges string
Definition: gpio.h:83
#define GPIO_EDGE_NONE_STR
no edge string
Definition: gpio.h:80
int gpioOpen(int gpio)
Open GPIO pin.
Definition: gpio.c:492
GPIO info structure.
Definition: gpio.h:98
int dir
gpio direction
Definition: gpio.h:102
#define GPIO_DIR_OUT
output
Definition: gpio.h:69
#define GPIO_DIR_IN_STR
input string
Definition: gpio.h:70
int gpioQuickRead(int fd)
Quick read GPIO pin&#39;s current value.
Definition: gpio.c:520
void gpioMakeDirname(int gpio, char buf[], size_t size)
Make GPIO directory name.
Definition: gpio.c:587
#define GPIO_EDGE_NONE
no edge
Definition: gpio.h:76
int gpioProbe(int gpio, gpio_info_t *p)
Safely probe GPIO parameters.
Definition: gpio.c:346
int pin
external header pin number
Definition: gpio.h:101
int gpioNotify(int fd, double timeout)
Notify on GPIO input value change.
Definition: gpio.c:442
#define GPIO_EDGE_RISING_STR
rising edge string
Definition: gpio.h:81
int gpioSetEdge(int gpio, int edge)
Set GPIO edge trigger type.
Definition: gpio.c:292
int gpioBitBang(int fd, byte_t pattern[], size_t bitCount, unsigned int usecIbd)
Bit-bang bits out a GPIO pin.
Definition: gpio.c:558
int gpioUnexport(int gpio)
Unexport (delete) a GPIO interface.
Definition: gpio.c:221
#define GPIO_EDGE_RISING
rising edge
Definition: gpio.h:77
int value
current value
Definition: gpio.h:105