Gordons Projects

--> Projects Top-Level GIT

Initial move to GIT
[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 [-g] <read/write/pwm/mode> ...\n"
46               "       gpio [-p] <read/write/mode> ...\n"
47               "       gpio export/edge/unexport/unexportall/exports ...\n"
48               "       gpio drive <group> <value>\n"
49               "       gpio load spi/i2c" ;
50
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 void doExports (void)
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   uid_t uid ;
330   gid_t gid ;
331
332   if (argc != 4)
333   {
334     fprintf (stderr, "Usage: %s edge pin mode\n", argv [0]) ;
335     exit (1) ;
336   }
337
338   pin = atoi (argv [2]) ;
339
340   mode = argv [3] ;
341
342 // Export the pin and set direction to input
343
344   if ((fd = fopen ("/sys/class/gpio/export", "w")) == NULL)
345   {
346     fprintf (stderr, "%s: Unable to open GPIO export interface: %s\n", argv [0], strerror (errno)) ;
347     exit (1) ;
348   }
349
350   fprintf (fd, "%d\n", pin) ;
351   fclose (fd) ;
352
353   sprintf (fName, "/sys/class/gpio/gpio%d/direction", pin) ;
354   if ((fd = fopen (fName, "w")) == NULL)
355   {
356     fprintf (stderr, "%s: Unable to open GPIO direction interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
357     exit (1) ;
358   }
359
360   fprintf (fd, "in\n") ;
361   fclose (fd) ;
362
363   sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
364   if ((fd = fopen (fName, "w")) == NULL)
365   {
366     fprintf (stderr, "%s: Unable to open GPIO edge interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
367     exit (1) ;
368   }
369
370   /**/ if (strcasecmp (mode, "none")    == 0)
371     fprintf (fd, "none\n") ;
372   else if (strcasecmp (mode, "rising")  == 0)
373     fprintf (fd, "rising\n") ;
374   else if (strcasecmp (mode, "falling") == 0)
375     fprintf (fd, "falling\n") ;
376   else if (strcasecmp (mode, "both")    == 0)
377     fprintf (fd, "both\n") ;
378   else
379   {
380     fprintf (stderr, "%s: Invalid mode: %s. Should be none, rising, falling or both\n", argv [1], mode) ;
381     exit (1) ;
382   }
383
384 // Change ownership so the current user can actually use it!
385
386   uid = getuid () ;
387   gid = getgid () ;
388
389   sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
390   if (chown (fName, uid, gid) != 0)
391   {
392     fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ;
393     exit (1) ;
394   }
395
396 // Also change ownership of the edge file
397
398   sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
399   if (chown (fName, uid, gid) != 0)
400   {
401     fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ;
402     exit (1) ;
403   }
404
405   fclose (fd) ;
406 }
407
408
409 /*
410  * doUnexport:
411  *      gpio unexport pin
412  *      This uses the /sys/class/gpio device interface.
413  *********************************************************************************
414  */
415
416 void doUnexport (int argc, char *argv [])
417 {
418   FILE *fd ;
419   int pin ;
420
421   if (argc != 3)
422   {
423     fprintf (stderr, "Usage: %s unexport pin\n", argv [0]) ;
424     exit (1) ;
425   }
426
427   pin = atoi (argv [2]) ;
428
429   if ((fd = fopen ("/sys/class/gpio/unexport", "w")) == NULL)
430   {
431     fprintf (stderr, "%s: Unable to open GPIO export interface\n", argv [0]) ;
432     exit (1) ;
433   }
434
435   fprintf (fd, "%d\n", pin) ;
436   fclose (fd) ;
437 }
438
439
440 /*
441  * doUnexportAll:
442  *      gpio unexportall
443  *      Un-Export all the GPIO pins.
444  *      This uses the /sys/class/gpio device interface.
445  *********************************************************************************
446  */
447
448 void doUnexportall (int argc, char *argv [])
449 {
450   FILE *fd ;
451   int pin ;
452
453   for (pin = 0 ; pin < 63 ; ++pin)
454   {
455     if ((fd = fopen ("/sys/class/gpio/unexport", "w")) == NULL)
456     {
457       fprintf (stderr, "%s: Unable to open GPIO export interface\n", argv [0]) ;
458       exit (1) ;
459     }
460     fprintf (fd, "%d\n", pin) ;
461     fclose (fd) ;
462   }
463 }
464
465
466 /*
467  * doMode:
468  *      gpio mode pin mode ...
469  *********************************************************************************
470  */
471
472 void doMode (int argc, char *argv [])
473 {
474   int pin ;
475   char *mode ;
476
477   if (argc != 4)
478   {
479     fprintf (stderr, "Usage: %s mode pin mode\n", argv [0]) ;
480     exit (1) ;
481   }
482
483   pin = atoi (argv [2]) ;
484
485   if ((wpMode == WPI_MODE_PINS) && ((pin < 0) || (pin >= NUM_PINS)))
486     return ;
487
488   mode = argv [3] ;
489
490   /**/ if (strcasecmp (mode, "in")   == 0)
491     pinMode (pin, INPUT) ;
492   else if (strcasecmp (mode, "out")  == 0)
493     pinMode (pin, OUTPUT) ;
494   else if (strcasecmp (mode, "pwm")  == 0)
495     pinMode (pin, PWM_OUTPUT) ;
496   else if (strcasecmp (mode, "up")   == 0)
497     pullUpDnControl (pin, PUD_UP) ;
498   else if (strcasecmp (mode, "down") == 0)
499     pullUpDnControl (pin, PUD_DOWN) ;
500   else if (strcasecmp (mode, "tri") == 0)
501     pullUpDnControl (pin, PUD_OFF) ;
502   else
503   {
504     fprintf (stderr, "%s: Invalid mode: %s. Should be in/out/pwm/up/down/tri\n", argv [1], mode) ;
505     exit (1) ;
506   }
507 }
508
509
510 /*
511  * doPadDrive:
512  *      gpio drive group value
513  *********************************************************************************
514  */
515
516 void doPadDrive (int argc, char *argv [])
517 {
518   int group, val ;
519
520   if (argc != 4)
521   {
522     fprintf (stderr, "Usage: %s drive group value\n", argv [0]) ;
523     exit (1) ;
524   }
525
526   group = atoi (argv [2]) ;
527   val   = atoi (argv [3]) ;
528
529   if ((group < 0) || (group > 2))
530   {
531     fprintf (stderr, "%s: drive group not 0, 1 or 2: %d\n", argv [0], group) ;
532     exit (1) ;
533   }
534
535   if ((val < 0) || (val > 7))
536   {
537     fprintf (stderr, "%s: drive value not 0-7: %d\n", argv [0], val) ;
538     exit (1) ;
539   }
540
541   setPadDrive (group, val) ;
542 }
543
544
545 /*
546  * doWrite:
547  *      gpio write pin value
548  *********************************************************************************
549  */
550
551 void doWrite (int argc, char *argv [])
552 {
553   int pin, val ;
554
555   if (argc != 4)
556   {
557     fprintf (stderr, "Usage: %s write pin value\n", argv [0]) ;
558     exit (1) ;
559   }
560
561   pin = atoi (argv [2]) ;
562
563   if ((wpMode == WPI_MODE_PINS) && ((pin < 0) || (pin >= NUM_PINS)))
564     return ;
565
566   val = atoi (argv [3]) ;
567
568   /**/ if (val == 0)
569     digitalWrite (pin, LOW) ;
570   else
571     digitalWrite (pin, HIGH) ;
572 }
573
574
575 /*
576  * doRead:
577  *      Read a pin and return the value
578  *********************************************************************************
579  */
580
581 void doRead (int argc, char *argv []) 
582 {
583   int pin, val ;
584
585   if (argc != 3)
586   {
587     fprintf (stderr, "Usage: %s read pin\n", argv [0]) ;
588     exit (1) ;
589   }
590
591   pin = atoi (argv [2]) ;
592
593   if ((wpMode == WPI_MODE_PINS) && ((pin < 0) || (pin >= NUM_PINS)))
594   {
595     printf ("0\n") ;
596     return ;
597   }
598
599   val = digitalRead (pin) ;
600
601   printf ("%s\n", val == 0 ? "0" : "1") ;
602 }
603
604
605 /*
606  * doPwm:
607  *      Output a PWM value on a pin
608  *********************************************************************************
609  */
610
611 void doPwm (int argc, char *argv [])
612 {
613   int pin, val ;
614
615   if (argc != 4)
616   {
617     fprintf (stderr, "Usage: %s pwm <pin> <value>\n", argv [0]) ;
618     exit (1) ;
619   }
620
621   pin = atoi (argv [2]) ;
622
623   if ((wpMode == WPI_MODE_PINS) && ((pin < 0) || (pin >= NUM_PINS)))
624     return ;
625
626   val = atoi (argv [3]) ;
627
628   pwmWrite (pin, val) ;
629 }
630
631
632 /*
633  * main:
634  *      Start here
635  *********************************************************************************
636  */
637
638 int main (int argc, char *argv [])
639 {
640   int i ;
641
642   if (argc == 1)
643   {
644     fprintf (stderr, "%s: %s\n", argv [0], usage) ;
645     return 1 ;
646   }
647
648   if (strcasecmp (argv [1], "-v") == 0)
649   {
650     printf ("gpio version: %s\n", VERSION) ;
651     printf ("Copyright (c) 2012 Gordon Henderson\n") ;
652     printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ;
653     printf ("For details type: %s -warranty\n", argv [0]) ;
654     return 0 ;
655   }
656
657   if (strcasecmp (argv [1], "-warranty") == 0)
658   {
659     printf ("gpio version: %s\n", VERSION) ;
660     printf ("Copyright (c) 2012 Gordon Henderson\n") ;
661     printf ("\n") ;
662     printf ("    This program is free software; you can redistribute it and/or modify\n") ;
663     printf ("    it under the terms of the GNU Leser General Public License as published\n") ;
664     printf ("    by the Free Software Foundation, either version 3 of the License, or\n") ;
665     printf ("    (at your option) any later version.\n") ;
666     printf ("\n") ;
667     printf ("    This program is distributed in the hope that it will be useful,\n") ;
668     printf ("    but WITHOUT ANY WARRANTY; without even the implied warranty of\n") ;
669     printf ("    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n") ;
670     printf ("    GNU Lesser General Public License for more details.\n") ;
671     printf ("\n") ;
672     printf ("    You should have received a copy of the GNU Lesser General Public License\n") ;
673     printf ("    along with this program. If not, see <http://www.gnu.org/licenses/>.\n") ;
674     printf ("\n") ;
675     return 0 ;
676   }
677
678   if (geteuid () != 0)
679   {
680     fprintf (stderr, "%s: Must be root to run. Program should be suid root. This is an error.\n", argv [0]) ;
681     return 1 ;
682   }
683
684 // Initial test for /sys/class/gpio operations:
685
686   /**/ if (strcasecmp (argv [1], "exports"    ) == 0)   { doExports () ;                return 0 ; }
687   else if (strcasecmp (argv [1], "export"     ) == 0)   { doExport (argc, argv) ;       return 0 ; }
688   else if (strcasecmp (argv [1], "edge"       ) == 0)   { doEdge (argc, argv) ;         return 0 ; }
689   else if (strcasecmp (argv [1], "unexportall") == 0)   { doUnexportall (argc, argv) ;  return 0 ; }
690   else if (strcasecmp (argv [1], "unexport"   ) == 0)   { doUnexport (argc, argv) ;     return 0 ; }
691   else if (strcasecmp (argv [1], "load"       ) == 0)   { doLoad (argc, argv) ;         return 0 ; }
692
693 // Check for -g argument
694
695   if (strcasecmp (argv [1], "-g") == 0)
696   {
697     if (wiringPiSetupGpio () == -1)
698     {
699       fprintf (stderr, "%s: Unable to initialise GPIO in GPIO mode.\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_GPIO ;
707   }
708
709 // Check for -p argument for PiFace
710
711   else if (strcasecmp (argv [1], "-p") == 0)
712   {
713     if (wiringPiSetupPiFaceForGpioProg () == -1)
714     {
715       fprintf (stderr, "%s: Unable to initialise PiFace.\n", argv [0]) ;
716       exit (1) ;
717     }
718
719     for (i = 2 ; i < argc ; ++i)
720       argv [i - 1] = argv [i] ;
721     --argc ;
722     wpMode = WPI_MODE_PIFACE ;
723   }
724
725 // Default to wiringPi mode
726
727   else
728   {
729     if (wiringPiSetup () == -1)
730     {
731       fprintf (stderr, "%s: Unable to initialise GPIO in wiringPi mode\n", argv [0]) ;
732       exit (1) ;
733     }
734     wpMode = WPI_MODE_PINS ;
735   }
736
737 // Check for wiring commands
738
739   /**/ if (strcasecmp (argv [1], "write"   ) == 0)
740     doWrite  (argc, argv) ;
741   else if (strcasecmp (argv [1], "read"    ) == 0)
742     doRead   (argc, argv) ;
743   else if (strcasecmp (argv [1], "mode"    ) == 0)
744     doMode   (argc, argv) ;
745   else if (strcasecmp (argv [1], "pwm"     ) == 0)
746     doPwm    (argc, argv) ;
747   else if (strcasecmp (argv [1], "drive"   ) == 0)
748     doPadDrive (argc, argv) ;
749   else
750   {
751     fprintf (stderr, "%s: Unknown command: %s. (read/write/pwm/mode/drive expected)\n", argv [0], argv [1]) ;
752     exit (1) ;
753   }
754   return 0 ;
755 }