Gordons Projects

--> Projects Top-Level GIT

2b6295335297405e2bebc3578b4c39daa03ec8fe
[wiringPi] / gpio / gpio.c
1 /*
2  * gpio.c:
3  *      Set-UID command-line interface to the Raspberry Pi's GPIO
4  *      Copyright (c) 2012 Gordon Henderson
5  ***********************************************************************
6  * This file is part of wiringPi:
7  *      https://projects.drogon.net/raspberry-pi/wiringpi/
8  *
9  *    wiringPi is free software: you can redistribute it and/or modify
10  *    it under the terms of the GNU Lesser General Public License as published by
11  *    the Free Software Foundation, either version 3 of the License, or
12  *    (at your option) any later version.
13  *
14  *    wiringPi is distributed in the hope that it will be useful,
15  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *    GNU Lesser General Public License for more details.
18  *
19  *    You should have received a copy of the GNU Lesser General Public License
20  *    along with wiringPi.  If not, see <http://www.gnu.org/licenses/>.
21  ***********************************************************************
22  */
23
24 #include <wiringPi.h>
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <fcntl.h>
34
35 #ifndef TRUE
36 #  define       TRUE    (1==1)
37 #  define       FALSE   (1==2)
38 #endif
39
40 #define VERSION "1.1"
41
42 static int wpMode ;
43
44 char *usage = "Usage: gpio -v\n"
45               "       gpio -h\n"
46               "       gpio [-g] <read/write/pwm/mode> ...\n"
47               "       gpio [-p] <read/write/mode> ...\n"
48               "       gpio export/edge/unexport/unexportall/exports ...\n"
49               "       gpio drive <group> <value>\n"
50               "       gpio load spi/i2c" ;
51
52
53 /*
54  * changeOwner:
55  *      Change the ownership of the file to the real userId of the calling
56  *      program so we can access it.
57  *********************************************************************************
58  */
59
60 static void changeOwner (char *cmd, char *file)
61 {
62   uid_t uid = getuid () ;
63   uid_t gid = getgid () ;
64
65   if (chown (file, uid, gid) != 0)
66   {
67     if (errno == ENOENT)        // Warn that it's not there
68       fprintf (stderr, "%s: Warning: File not present: %s\n", cmd, file) ;
69     else
70     {
71       fprintf (stderr, "%s: Unable to change ownership of %s: %s\n", cmd, file, strerror (errno)) ;
72       exit (1) ;
73     }
74   }
75 }
76
77
78 /*
79  * moduleLoaded:
80  *      Return true/false if the supplied module is loaded
81  *********************************************************************************
82  */
83
84 static int moduleLoaded (char *modName)
85 {
86   int len   = strlen (modName) ;
87   int found = FALSE ;
88   FILE *fd = fopen ("/proc/modules", "r") ;
89   char line [80] ;
90
91   if (fd == NULL)
92   {
93     fprintf (stderr, "gpio: Unable to check modules: %s\n", strerror (errno)) ;
94     exit (1) ;
95   }
96
97   while (fgets (line, 80, fd) != NULL)
98   {
99     if (strncmp (line, modName, len) != 0)
100       continue ;
101
102     found = TRUE ;
103     break ;
104   }
105
106   fclose (fd) ;
107
108   return found ;
109 }
110
111
112 /*
113  * doLoad:
114  *      Load either the spi or i2c modules and change device ownerships, etc.
115  *********************************************************************************
116  */
117
118 static void _doLoadUsage (char *argv [])
119 {
120   fprintf (stderr, "Usage: %s load <spi/i2c>\n", argv [0]) ;
121   exit (1) ;
122 }
123
124 static void doLoad (int argc, char *argv [])
125 {
126   char *module ;
127   char cmd [80] ;
128   char *file1, *file2 ;
129
130   if (argc != 3)
131     _doLoadUsage (argv) ;
132
133   /**/ if (strcasecmp (argv [2], "spi") == 0)
134   {
135     module = "spi_bcm2708" ;
136     file1  = "/dev/spidev0.0" ;
137     file2  = "/dev/spidev0.1" ;
138   }
139   else if (strcasecmp (argv [2], "i2c") == 0)
140   {
141     module = "i2c_bcm2708" ;
142     file1  = "/dev/i2c-0" ;
143     file2  = "/dev/i2c-1" ;
144   }
145   else
146     _doLoadUsage (argv) ;
147
148   if (!moduleLoaded (module))
149   {
150     sprintf (cmd, "modprobe %s", module) ;
151     system (cmd) ;
152   }
153
154   if (!moduleLoaded (module))
155   {
156     fprintf (stderr, "%s: Unable to load %s\n", argv [0], module) ;
157     exit (1) ;
158   }
159
160   sleep (1) ;   // To let things get settled
161
162   changeOwner (argv [0], file1) ;
163   changeOwner (argv [0], file2) ;
164 }
165
166
167
168 /*
169  * doExports:
170  *      List all GPIO exports
171  *********************************************************************************
172  */
173
174 static void doExports (int argc, char *argv [])
175 {
176   int fd ;
177   int i, l, first ;
178   char fName [128] ;
179   char buf [16] ;
180
181 // Rather crude, but who knows what others are up to...
182
183   for (first = 0, i = 0 ; i < 64 ; ++i)
184   {
185
186 // Try to read the direction
187
188     sprintf (fName, "/sys/class/gpio/gpio%d/direction", i) ;
189     if ((fd = open (fName, O_RDONLY)) == -1)
190       continue ;
191
192     if (first == 0)
193     {
194       ++first ;
195       printf ("GPIO Pins exported:\n") ;
196     }
197
198     printf ("%4d: ", i) ;
199
200     if ((l = read (fd, buf, 16)) == 0)
201       sprintf (buf, "%s", "?") ;
202  
203     buf [l] = 0 ;
204     if ((buf [strlen (buf) - 1]) == '\n')
205       buf [strlen (buf) - 1] = 0 ;
206
207     printf ("%-3s", buf) ;
208
209     close (fd) ;
210
211 // Try to Read the value
212
213     sprintf (fName, "/sys/class/gpio/gpio%d/value", i) ;
214     if ((fd = open (fName, O_RDONLY)) == -1)
215     {
216       printf ("No Value file (huh?)\n") ;
217       continue ;
218     }
219
220     if ((l = read (fd, buf, 16)) == 0)
221       sprintf (buf, "%s", "?") ;
222
223     buf [l] = 0 ;
224     if ((buf [strlen (buf) - 1]) == '\n')
225       buf [strlen (buf) - 1] = 0 ;
226
227     printf ("  %s", buf) ;
228
229 // Read any edge trigger file
230
231     sprintf (fName, "/sys/class/gpio/gpio%d/edge", i) ;
232     if ((fd = open (fName, O_RDONLY)) == -1)
233     {
234       printf ("\n") ;
235       continue ;
236     }
237
238     if ((l = read (fd, buf, 16)) == 0)
239       sprintf (buf, "%s", "?") ;
240
241     buf [l] = 0 ;
242     if ((buf [strlen (buf) - 1]) == '\n')
243       buf [strlen (buf) - 1] = 0 ;
244
245     printf ("  %-8s\n", buf) ;
246
247     close (fd) ;
248   }
249 }
250
251
252 /*
253  * doExport:
254  *      gpio export pin mode
255  *      This uses the /sys/class/gpio device interface.
256  *********************************************************************************
257  */
258
259 void doExport (int argc, char *argv [])
260 {
261   FILE *fd ;
262   int pin ;
263   char *mode ;
264   char fName [128] ;
265
266   if (argc != 4)
267   {
268     fprintf (stderr, "Usage: %s export pin mode\n", argv [0]) ;
269     exit (1) ;
270   }
271
272   pin = atoi (argv [2]) ;
273
274   mode = argv [3] ;
275
276   if ((fd = fopen ("/sys/class/gpio/export", "w")) == NULL)
277   {
278     fprintf (stderr, "%s: Unable to open GPIO export interface: %s\n", argv [0], strerror (errno)) ;
279     exit (1) ;
280   }
281
282   fprintf (fd, "%d\n", pin) ;
283   fclose (fd) ;
284
285   sprintf (fName, "/sys/class/gpio/gpio%d/direction", pin) ;
286   if ((fd = fopen (fName, "w")) == NULL)
287   {
288     fprintf (stderr, "%s: Unable to open GPIO direction interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
289     exit (1) ;
290   }
291
292   /**/ if ((strcasecmp (mode, "in")  == 0) || (strcasecmp (mode, "input")  == 0))
293     fprintf (fd, "in\n") ;
294   else if ((strcasecmp (mode, "out") == 0) || (strcasecmp (mode, "output") == 0))
295     fprintf (fd, "out\n") ;
296   else
297   {
298     fprintf (stderr, "%s: Invalid mode: %s. Should be in or out\n", argv [1], mode) ;
299     exit (1) ;
300   }
301
302   fclose (fd) ;
303
304 // Change ownership so the current user can actually use it!
305
306   sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
307   changeOwner (argv [0], fName) ;
308
309   sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
310   changeOwner (argv [0], fName) ;
311
312 }
313
314
315 /*
316  * doEdge:
317  *      gpio edge pin mode
318  *      Easy access to changing the edge trigger on a GPIO pin
319  *      This uses the /sys/class/gpio device interface.
320  *********************************************************************************
321  */
322
323 void doEdge (int argc, char *argv [])
324 {
325   FILE *fd ;
326   int pin ;
327   char *mode ;
328   char fName [128] ;
329
330   if (argc != 4)
331   {
332     fprintf (stderr, "Usage: %s edge pin mode\n", argv [0]) ;
333     exit (1) ;
334   }
335
336   pin  = atoi (argv [2]) ;
337   mode = argv [3] ;
338
339 // Export the pin and set direction to input
340
341   if ((fd = fopen ("/sys/class/gpio/export", "w")) == NULL)
342   {
343     fprintf (stderr, "%s: Unable to open GPIO export interface: %s\n", argv [0], strerror (errno)) ;
344     exit (1) ;
345   }
346
347   fprintf (fd, "%d\n", pin) ;
348   fclose (fd) ;
349
350   sprintf (fName, "/sys/class/gpio/gpio%d/direction", pin) ;
351   if ((fd = fopen (fName, "w")) == NULL)
352   {
353     fprintf (stderr, "%s: Unable to open GPIO direction interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
354     exit (1) ;
355   }
356
357   fprintf (fd, "in\n") ;
358   fclose (fd) ;
359
360   sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
361   if ((fd = fopen (fName, "w")) == NULL)
362   {
363     fprintf (stderr, "%s: Unable to open GPIO edge interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
364     exit (1) ;
365   }
366
367   /**/ if (strcasecmp (mode, "none")    == 0) fprintf (fd, "none\n") ;
368   else if (strcasecmp (mode, "rising")  == 0) fprintf (fd, "rising\n") ;
369   else if (strcasecmp (mode, "falling") == 0) fprintf (fd, "falling\n") ;
370   else if (strcasecmp (mode, "both")    == 0) fprintf (fd, "both\n") ;
371   else
372   {
373     fprintf (stderr, "%s: Invalid mode: %s. Should be none, rising, falling or both\n", argv [1], mode) ;
374     exit (1) ;
375   }
376
377 // Change ownership of the value and edge files, so the current user can actually use it!
378
379   sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
380   changeOwner (argv [0], fName) ;
381
382   sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
383   changeOwner (argv [0], fName) ;
384
385   fclose (fd) ;
386 }
387
388
389 /*
390  * doUnexport:
391  *      gpio unexport pin
392  *      This uses the /sys/class/gpio device interface.
393  *********************************************************************************
394  */
395
396 void doUnexport (int argc, char *argv [])
397 {
398   FILE *fd ;
399   int pin ;
400
401   if (argc != 3)
402   {
403     fprintf (stderr, "Usage: %s unexport pin\n", argv [0]) ;
404     exit (1) ;
405   }
406
407   pin = atoi (argv [2]) ;
408
409   if ((fd = fopen ("/sys/class/gpio/unexport", "w")) == NULL)
410   {
411     fprintf (stderr, "%s: Unable to open GPIO export interface\n", argv [0]) ;
412     exit (1) ;
413   }
414
415   fprintf (fd, "%d\n", pin) ;
416   fclose (fd) ;
417 }
418
419
420 /*
421  * doUnexportAll:
422  *      gpio unexportall
423  *      Un-Export all the GPIO pins.
424  *      This uses the /sys/class/gpio device interface.
425  *********************************************************************************
426  */
427
428 void doUnexportall (int argc, char *argv [])
429 {
430   FILE *fd ;
431   int pin ;
432
433   for (pin = 0 ; pin < 63 ; ++pin)
434   {
435     if ((fd = fopen ("/sys/class/gpio/unexport", "w")) == NULL)
436     {
437       fprintf (stderr, "%s: Unable to open GPIO export interface\n", argv [0]) ;
438       exit (1) ;
439     }
440     fprintf (fd, "%d\n", pin) ;
441     fclose (fd) ;
442   }
443 }
444
445
446 /*
447  * doMode:
448  *      gpio mode pin mode ...
449  *********************************************************************************
450  */
451
452 void doMode (int argc, char *argv [])
453 {
454   int pin ;
455   char *mode ;
456
457   if (argc != 4)
458   {
459     fprintf (stderr, "Usage: %s mode pin mode\n", argv [0]) ;
460     exit (1) ;
461   }
462
463   pin = atoi (argv [2]) ;
464
465   if ((wpMode == WPI_MODE_PINS) && ((pin < 0) || (pin >= NUM_PINS)))
466     return ;
467
468   mode = argv [3] ;
469
470   /**/ if (strcasecmp (mode, "in")   == 0) pinMode         (pin, INPUT) ;
471   else if (strcasecmp (mode, "out")  == 0) pinMode         (pin, OUTPUT) ;
472   else if (strcasecmp (mode, "pwm")  == 0) pinMode         (pin, PWM_OUTPUT) ;
473   else if (strcasecmp (mode, "up")   == 0) pullUpDnControl (pin, PUD_UP) ;
474   else if (strcasecmp (mode, "down") == 0) pullUpDnControl (pin, PUD_DOWN) ;
475   else if (strcasecmp (mode, "tri")  == 0) pullUpDnControl (pin, PUD_OFF) ;
476   else
477   {
478     fprintf (stderr, "%s: Invalid mode: %s. Should be in/out/pwm/up/down/tri\n", argv [1], mode) ;
479     exit (1) ;
480   }
481 }
482
483
484 /*
485  * doPadDrive:
486  *      gpio drive group value
487  *********************************************************************************
488  */
489
490 void doPadDrive (int argc, char *argv [])
491 {
492   int group, val ;
493
494   if (argc != 4)
495   {
496     fprintf (stderr, "Usage: %s drive group value\n", argv [0]) ;
497     exit (1) ;
498   }
499
500   group = atoi (argv [2]) ;
501   val   = atoi (argv [3]) ;
502
503   if ((group < 0) || (group > 2))
504   {
505     fprintf (stderr, "%s: drive group not 0, 1 or 2: %d\n", argv [0], group) ;
506     exit (1) ;
507   }
508
509   if ((val < 0) || (val > 7))
510   {
511     fprintf (stderr, "%s: drive value not 0-7: %d\n", argv [0], val) ;
512     exit (1) ;
513   }
514
515   setPadDrive (group, val) ;
516 }
517
518
519 /*
520  * doWrite:
521  *      gpio write pin value
522  *********************************************************************************
523  */
524
525 void doWrite (int argc, char *argv [])
526 {
527   int pin, val ;
528
529   if (argc != 4)
530   {
531     fprintf (stderr, "Usage: %s write pin value\n", argv [0]) ;
532     exit (1) ;
533   }
534
535   pin = atoi (argv [2]) ;
536
537   if ((wpMode == WPI_MODE_PINS) && ((pin < 0) || (pin >= NUM_PINS)))
538     return ;
539
540   val = atoi (argv [3]) ;
541
542   /**/ if (val == 0)
543     digitalWrite (pin, LOW) ;
544   else
545     digitalWrite (pin, HIGH) ;
546 }
547
548
549 /*
550  * doRead:
551  *      Read a pin and return the value
552  *********************************************************************************
553  */
554
555 void doRead (int argc, char *argv []) 
556 {
557   int pin, val ;
558
559   if (argc != 3)
560   {
561     fprintf (stderr, "Usage: %s read pin\n", argv [0]) ;
562     exit (1) ;
563   }
564
565   pin = atoi (argv [2]) ;
566
567   if ((wpMode == WPI_MODE_PINS) && ((pin < 0) || (pin >= NUM_PINS)))
568   {
569     printf ("0\n") ;
570     return ;
571   }
572
573   val = digitalRead (pin) ;
574
575   printf ("%s\n", val == 0 ? "0" : "1") ;
576 }
577
578
579 /*
580  * doPwm:
581  *      Output a PWM value on a pin
582  *********************************************************************************
583  */
584
585 void doPwm (int argc, char *argv [])
586 {
587   int pin, val ;
588
589   if (argc != 4)
590   {
591     fprintf (stderr, "Usage: %s pwm <pin> <value>\n", argv [0]) ;
592     exit (1) ;
593   }
594
595   pin = atoi (argv [2]) ;
596
597   if ((wpMode == WPI_MODE_PINS) && ((pin < 0) || (pin >= NUM_PINS)))
598     return ;
599
600   val = atoi (argv [3]) ;
601
602   pwmWrite (pin, val) ;
603 }
604
605
606 /*
607  * main:
608  *      Start here
609  *********************************************************************************
610  */
611
612 int main (int argc, char *argv [])
613 {
614   int i ;
615
616   if (argc == 1)
617   {
618     fprintf (stderr, "%s: %s\n", argv [0], usage) ;
619     return 1 ;
620   }
621
622   if (strcasecmp (argv [1], "-h") == 0)
623   {
624     printf ("%s: %s\n", argv [0], usage) ;
625     return 0 ;
626   }
627
628   if (strcasecmp (argv [1], "-v") == 0)
629   {
630     printf ("gpio version: %s\n", VERSION) ;
631     printf ("Copyright (c) 2012 Gordon Henderson\n") ;
632     printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ;
633     printf ("For details type: %s -warranty\n", argv [0]) ;
634     return 0 ;
635   }
636
637   if (strcasecmp (argv [1], "-warranty") == 0)
638   {
639     printf ("gpio version: %s\n", VERSION) ;
640     printf ("Copyright (c) 2012 Gordon Henderson\n") ;
641     printf ("\n") ;
642     printf ("    This program is free software; you can redistribute it and/or modify\n") ;
643     printf ("    it under the terms of the GNU Leser General Public License as published\n") ;
644     printf ("    by the Free Software Foundation, either version 3 of the License, or\n") ;
645     printf ("    (at your option) any later version.\n") ;
646     printf ("\n") ;
647     printf ("    This program is distributed in the hope that it will be useful,\n") ;
648     printf ("    but WITHOUT ANY WARRANTY; without even the implied warranty of\n") ;
649     printf ("    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n") ;
650     printf ("    GNU Lesser General Public License for more details.\n") ;
651     printf ("\n") ;
652     printf ("    You should have received a copy of the GNU Lesser General Public License\n") ;
653     printf ("    along with this program. If not, see <http://www.gnu.org/licenses/>.\n") ;
654     printf ("\n") ;
655     return 0 ;
656   }
657
658   if (geteuid () != 0)
659   {
660     fprintf (stderr, "%s: Must be root to run. Program should be suid root. This is an error.\n", argv [0]) ;
661     return 1 ;
662   }
663
664 // Initial test for /sys/class/gpio operations:
665
666   /**/ if (strcasecmp (argv [1], "exports"    ) == 0)   { doExports     (argc, argv) ;  return 0 ; }
667   else if (strcasecmp (argv [1], "export"     ) == 0)   { doExport      (argc, argv) ;  return 0 ; }
668   else if (strcasecmp (argv [1], "edge"       ) == 0)   { doEdge        (argc, argv) ;  return 0 ; }
669   else if (strcasecmp (argv [1], "unexportall") == 0)   { doUnexportall (argc, argv) ;  return 0 ; }
670   else if (strcasecmp (argv [1], "unexport"   ) == 0)   { doUnexport    (argc, argv) ;  return 0 ; }
671
672 // Check for drive or load commands:
673
674   if (strcasecmp (argv [1], "drive") == 0)      { doPadDrive (argc, argv) ; return 0 ; }
675   if (strcasecmp (argv [1], "load" ) == 0)      { doLoad     (argc, argv) ; return 0 ; }
676
677 // Check for -g argument
678
679   if (strcasecmp (argv [1], "-g") == 0)
680   {
681     if (wiringPiSetupGpio () == -1)
682     {
683       fprintf (stderr, "%s: Unable to initialise GPIO mode.\n", argv [0]) ;
684       exit (1) ;
685     }
686
687     for (i = 2 ; i < argc ; ++i)
688       argv [i - 1] = argv [i] ;
689     --argc ;
690     wpMode = WPI_MODE_GPIO ;
691   }
692
693 // Check for -p argument for PiFace
694
695   else if (strcasecmp (argv [1], "-p") == 0)
696   {
697     if (wiringPiSetupPiFaceForGpioProg () == -1)
698     {
699       fprintf (stderr, "%s: Unable to initialise PiFace.\n", argv [0]) ;
700       exit (1) ;
701     }
702
703     for (i = 2 ; i < argc ; ++i)
704       argv [i - 1] = argv [i] ;
705     --argc ;
706     wpMode = WPI_MODE_PIFACE ;
707   }
708
709 // Default to wiringPi mode
710
711   else
712   {
713     if (wiringPiSetup () == -1)
714     {
715       fprintf (stderr, "%s: Unable to initialise wiringPi mode\n", argv [0]) ;
716       exit (1) ;
717     }
718     wpMode = WPI_MODE_PINS ;
719   }
720
721 // Check for wiring commands
722
723   /**/ if (strcasecmp (argv [1], "read" ) == 0) doRead     (argc, argv) ;
724   else if (strcasecmp (argv [1], "write") == 0) doWrite    (argc, argv) ;
725   else if (strcasecmp (argv [1], "pwm"  ) == 0) doPwm      (argc, argv) ;
726   else if (strcasecmp (argv [1], "mode" ) == 0) doMode     (argc, argv) ;
727   else
728   {
729     fprintf (stderr, "%s: Unknown command: %s.\n", argv [0], argv [1]) ;
730     exit (1) ;
731   }
732   return 0 ;
733 }