blob: b1f60a0ad100203f86e5fb2581b48ffd5e782c64 [file] [log] [blame]
Gordon Hendersonbf0ad862012-08-16 15:04:43 +01001/*
2 * gpio.c:
Gordon Henderson99095e32012-08-27 20:56:14 +01003 * Swiss-Army-Knife, Set-UID command-line interface to the Raspberry
4 * Pi's GPIO.
Gordon Hendersone687f3f2017-01-24 12:13:39 +00005 * Copyright (c) 2012-2017 Gordon Henderson
Gordon Hendersonbf0ad862012-08-16 15:04:43 +01006 ***********************************************************************
7 * This file is part of wiringPi:
8 * https://projects.drogon.net/raspberry-pi/wiringpi/
9 *
10 * wiringPi is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * wiringPi is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
22 ***********************************************************************
23 */
Gordon Hendersonbf0ad862012-08-16 15:04:43 +010024#include <stdio.h>
25#include <stdlib.h>
26#include <stdint.h>
Gordon Hendersonda384432013-05-13 19:43:26 +010027#include <ctype.h>
Gordon Hendersonbf0ad862012-08-16 15:04:43 +010028#include <string.h>
29#include <unistd.h>
30#include <errno.h>
Gordon Hendersonbf0ad862012-08-16 15:04:43 +010031#include <fcntl.h>
Gordon Hendersonda384432013-05-13 19:43:26 +010032#include <sys/types.h>
33#include <sys/stat.h>
Gordon Hendersonbf0ad862012-08-16 15:04:43 +010034
Gordon Henderson99095e32012-08-27 20:56:14 +010035#include <wiringPi.h>
Gordon Hendersonda384432013-05-13 19:43:26 +010036
Gordon Hendersone687f3f2017-01-24 12:13:39 +000037#include "../version.h"
Gordon Henderson99095e32012-08-27 20:56:14 +010038
Gordon Henderson13bbba72013-01-14 11:31:56 +000039extern int wiringPiDebug ;
40
Gordon Henderson05e2f672014-05-20 11:43:07 +010041// External functions I can't be bothered creating a separate .h file for:
Yang Deokgyu5106f2a2019-09-20 12:27:57 +090042extern void doReadall (int argc, char *argv []);
Gordon Hendersonb0a60c32016-02-29 06:57:38 +000043extern void doAllReadall (void) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +090044extern void doUnexport (int argc, char *agrv []);
Gordon Henderson05e2f672014-05-20 11:43:07 +010045
Gordon Hendersonbf0ad862012-08-16 15:04:43 +010046#ifndef TRUE
47# define TRUE (1==1)
48# define FALSE (1==2)
49#endif
50
Gordon Hendersondf453882014-07-17 22:23:57 +010051#define PI_USB_POWER_CONTROL 38
joshua-yang4b08e7f2019-02-21 12:05:24 +090052#define I2CDETECT "i2cdetect"
53#define MODPROBE "modprobe"
54#define RMMOD "rmmod"
Gordon Hendersonbf0ad862012-08-16 15:04:43 +010055
Gordon Henderson27698762013-06-27 21:51:55 +010056int wpMode ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +010057
58char *usage = "Usage: gpio -v\n"
joshua-yang4b08e7f2019-02-21 12:05:24 +090059 " gpio -h\n"
60 " gpio [-g|-1] ...\n"
61 " gpio [-d] ...\n"
joshua-yang4b08e7f2019-02-21 12:05:24 +090062 " gpio [-p] <read/write/wb> ...\n"
Deokgyu Yang89cf23c2020-03-19 17:21:21 +090063 " gpio <read/write/aread/pwm/clock/mode> ...\n"
joshua-yang4b08e7f2019-02-21 12:05:24 +090064 " gpio <toggle/blink> <pin>\n"
Deokgyu Yang89cf23c2020-03-19 17:21:21 +090065 " gpio readall [-a|--all]\n"
joshua-yang4b08e7f2019-02-21 12:05:24 +090066 " gpio unexportall/exports\n"
67 " gpio export/edge/unexport ...\n"
68 " gpio wfi <pin> <mode>\n"
69 " gpio drive <pin> <value>\n"
joshua-yang4b08e7f2019-02-21 12:05:24 +090070 " gpio pwmr <range> \n"
71 " gpio pwmc <divider> \n"
72 " gpio load spi/i2c\n"
73 " gpio unload spi/i2c\n"
74 " gpio i2cd/i2cdetect\n"
75 " gpio rbx/rbd\n"
Deokgyu Yang89cf23c2020-03-19 17:21:21 +090076 " gpio wb <value>\n";
Gordon Hendersonbf0ad862012-08-16 15:04:43 +010077
78
Gordon Henderson6fba4032014-06-24 19:23:31 +010079#ifdef NOT_FOR_NOW
Gordon Hendersonbf0ad862012-08-16 15:04:43 +010080/*
Gordon Hendersonf18c8f72013-08-03 23:53:35 +010081 * decodePin:
82 * Decode a pin "number" which can actually be a pin name to represent
83 * one of the Pi's on-board pins.
84 *********************************************************************************
85 */
Gordon Hendersonf18c8f72013-08-03 23:53:35 +010086static int decodePin (const char *str)
87{
joshua-yang4b08e7f2019-02-21 12:05:24 +090088 // The first case - see if it's a number:
89 if (isdigit (str [0]))
90 return atoi (str) ;
Gordon Hendersonf18c8f72013-08-03 23:53:35 +010091
joshua-yang4b08e7f2019-02-21 12:05:24 +090092 return 0 ;
Gordon Hendersonf18c8f72013-08-03 23:53:35 +010093}
Gordon Henderson6fba4032014-06-24 19:23:31 +010094#endif
Gordon Hendersonf18c8f72013-08-03 23:53:35 +010095
96
97/*
Gordon Hendersonb1dfc182016-12-12 14:19:55 +000098 * findExecutable:
99 * Code to locate the path to the given executable. We have a fixed list
100 * of locations to try which completely overrides any $PATH environment.
101 * This may be detrimental, however it avoids the reliance on $PATH
102 * which may be a security issue when this program is run a set-uid-root.
103 *********************************************************************************
104 */
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000105static const char *searchPath [] =
106{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900107 "/sbin",
108 "/usr/sbin",
109 "/bin",
110 "/usr/bin",
111 NULL,
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000112} ;
113
114static char *findExecutable (const char *progName)
115{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900116 static char *path = NULL ;
117 int len = strlen (progName) ;
118 int i = 0 ;
119 struct stat statBuf ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000120
joshua-yang4b08e7f2019-02-21 12:05:24 +0900121 for (i = 0 ; searchPath [i] != NULL ; ++i) {
122 path = malloc (strlen (searchPath [i]) + len + 2) ;
123 sprintf (path, "%s/%s", searchPath [i], progName) ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000124
joshua-yang4b08e7f2019-02-21 12:05:24 +0900125 if (stat (path, &statBuf) == 0)
126 return path ;
127 free (path) ;
128 }
129 return NULL ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000130}
131
132
133/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100134 * changeOwner:
135 * Change the ownership of the file to the real userId of the calling
136 * program so we can access it.
137 *********************************************************************************
138 */
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100139static void changeOwner (char *cmd, char *file)
140{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900141 uid_t uid = getuid () ;
142 uid_t gid = getgid () ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100143
joshua-yang4b08e7f2019-02-21 12:05:24 +0900144 if (chown (file, uid, gid) != 0) {
145 // Removed (ignoring) the check for not existing as I'm fed-up with morons telling me that
146 // the warning message is an error.
147 if (errno != ENOENT)
148 fprintf (stderr, "%s: Unable to change ownership of %s: %s\n",
149 cmd, file, strerror (errno)) ;
150 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100151}
152
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100153/*
154 * doLoad:
155 * Load either the spi or i2c modules and change device ownerships, etc.
156 *********************************************************************************
157 */
Gordon Hendersonf6c40cb2015-09-24 22:35:31 +0100158static void checkDevTree (char *argv [])
159{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900160 struct stat statBuf ;
Gordon Hendersonf6c40cb2015-09-24 22:35:31 +0100161
joshua-yang4b08e7f2019-02-21 12:05:24 +0900162 // We're on a devtree system ...
163 if (stat ("/proc/device-tree", &statBuf) == 0) {
164 fprintf (stderr,
165 "%s: Unable to load/unload modules as this kernel has the device tree enabled.\n"
166 " You need to edit /etc/modprobe.d/blacklist-odroid.conf or update /media/models.dts file.\n"
167 " If you want to use SPI, you should find out spidev module line at the blacklist-odroid.conf\n"
168 " and uncomment that. Then reboot to enable the module.\n\n"
169 " Please refer to our wiki page:\n"
170 " https://wiki.odroid.com/start\n", argv [0]) ;
171 exit (1) ;
172 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100173}
174
Luke Go2ee8a0d2019-07-08 15:37:07 +0900175static void doLoad (int UNU argc, char *argv [])
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100176{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900177 checkDevTree (argv) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100178}
179
180
Gordon Henderson183c5a62012-10-21 15:25:16 +0100181/*
Gordon Hendersoneb1fc2c2015-01-30 18:14:49 +0000182 * doUnLoad:
183 * Un-Load either the spi or i2c modules and change device ownerships, etc.
184 *********************************************************************************
185 */
Luke Go2ee8a0d2019-07-08 15:37:07 +0900186static void doUnLoad (int UNU argc, char *argv [])
Gordon Hendersoneb1fc2c2015-01-30 18:14:49 +0000187{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900188 checkDevTree (argv) ;
Gordon Hendersoneb1fc2c2015-01-30 18:14:49 +0000189}
190
191
192/*
Gordon Hendersonda384432013-05-13 19:43:26 +0100193 * doI2Cdetect:
194 * Run the i2cdetect command with the right runes for this Pi revision
195 *********************************************************************************
196 */
Gordon Hendersone687f3f2017-01-24 12:13:39 +0000197static void doI2Cdetect (UNU int argc, char *argv [])
Gordon Hendersonda384432013-05-13 19:43:26 +0100198{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900199 int model, rev, mem, maker, overVolted, port;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900200 char *c, *command ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100201
joshua-yang4b08e7f2019-02-21 12:05:24 +0900202 piBoardId(&model, &rev, &mem, &maker, &overVolted);
Gordon Hendersonda384432013-05-13 19:43:26 +0100203
joshua-yang4b08e7f2019-02-21 12:05:24 +0900204 switch (model) {
Deokgyu Yang912e3d92020-08-24 12:23:50 +0900205 case MODEL_ODROID_C1:
206 case MODEL_ODROID_C2:
Deokgyu Yang54aca3f2020-09-07 17:51:46 +0900207 if (cmpKernelVersion(KERN_NUM_TO_MAJOR, 4))
208 port = 0;
209 else
210 port = 1;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900211 break;
Deokgyu Yang912e3d92020-08-24 12:23:50 +0900212 case MODEL_ODROID_XU3:
Deokgyu Yang5ebe86a2020-08-24 14:48:59 +0900213 if (cmpKernelVersion(KERN_NUM_TO_MAJOR, 5))
Deokgyu Yang912e3d92020-08-24 12:23:50 +0900214 port = 0;
215 else
216 port = 1;
217 break;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900218 case MODEL_ODROID_N1:
joshua-yang4b08e7f2019-02-21 12:05:24 +0900219 port = 4;
220 break;
221 case MODEL_ODROID_N2:
Deokgyu Yang912e3d92020-08-24 12:23:50 +0900222 case MODEL_ODROID_C4:
Deokgyu Yange94695f2020-11-13 12:56:17 +0900223 case MODEL_ODROID_HC4:
Deokgyu Yang912e3d92020-08-24 12:23:50 +0900224 if (cmpKernelVersion(KERN_NUM_TO_REVISION, 4, 9, 230))
225 port = 0;
226 else
227 port = 2;
Joshua Yang964b4222019-07-09 16:00:28 +0900228 break;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900229 default:
230 break;
231 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100232
joshua-yang4b08e7f2019-02-21 12:05:24 +0900233 if ((c = findExecutable (I2CDETECT)) == NULL) {
234 fprintf (stderr, "%s: Unable to find i2cdetect command: %s\n", argv [0], strerror (errno)) ;
235 return ;
236 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100237
Joshua Yang964b4222019-07-09 16:00:28 +0900238 switch (model) {
239 case MODEL_ODROID_C1:
240 case MODEL_ODROID_C2:
joshua-yang4b08e7f2019-02-21 12:05:24 +0900241 if (!moduleLoaded (AML_MODULE_I2C)) {
242 fprintf (stderr, "%s: The I2C kernel module(s) are not loaded.\n", argv [0]) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900243 }
Joshua Yang964b4222019-07-09 16:00:28 +0900244 break;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900245 default:
246 break;
247 }
248
249 command = malloc (strlen (c) + 16) ;
250 sprintf (command, "%s -y %d", c, port) ;
251 if (system (command) < 0)
252 fprintf (stderr, "%s: Unable to run i2cdetect: %s\n", argv [0], strerror (errno)) ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100253}
254
255
256/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100257 * doExports:
258 * List all GPIO exports
259 *********************************************************************************
260 */
Gordon Hendersone687f3f2017-01-24 12:13:39 +0000261static void doExports (UNU int argc, UNU char *argv [])
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100262{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900263 int fd ;
264 int i, l, first ;
265 char fName [128] ;
266 char buf [16] ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100267
joshua-yang4b08e7f2019-02-21 12:05:24 +0900268 // Crude, but effective
269 for (first = 0, i = 0 ; i < 256 ; ++i) {
270 // Try to read the direction
271 sprintf (fName, "/sys/class/gpio/gpio%d/direction", i) ;
272 if ((fd = open (fName, O_RDONLY)) == -1)
273 continue ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100274
joshua-yang4b08e7f2019-02-21 12:05:24 +0900275 if (first == 0) {
276 ++first ;
277 printf ("GPIO Pins exported:\n") ;
278 }
279 printf ("%4d: ", i) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100280
joshua-yang4b08e7f2019-02-21 12:05:24 +0900281 if ((l = read (fd, buf, 16)) == 0)
282 sprintf (buf, "%s", "?") ;
Joshua Yang6e7a6e62019-07-09 15:57:26 +0900283
joshua-yang4b08e7f2019-02-21 12:05:24 +0900284 buf [l] = 0 ;
285 if ((buf [strlen (buf) - 1]) == '\n')
286 buf [strlen (buf) - 1] = 0 ;
287 printf ("%-3s", buf) ;
288 close (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100289
joshua-yang4b08e7f2019-02-21 12:05:24 +0900290 // Try to Read the value
291 sprintf (fName, "/sys/class/gpio/gpio%d/value", i) ;
292 if ((fd = open (fName, O_RDONLY)) == -1) {
293 printf ("No Value file (huh?)\n") ;
294 continue ;
295 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100296
joshua-yang4b08e7f2019-02-21 12:05:24 +0900297 if ((l = read (fd, buf, 16)) == 0)
298 sprintf (buf, "%s", "?") ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100299
joshua-yang4b08e7f2019-02-21 12:05:24 +0900300 buf [l] = 0 ;
301 if ((buf [strlen (buf) - 1]) == '\n')
302 buf [strlen (buf) - 1] = 0 ;
303 printf (" %s", buf) ;
304 close (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100305
joshua-yang4b08e7f2019-02-21 12:05:24 +0900306 // Read any edge trigger file
307 sprintf (fName, "/sys/class/gpio/gpio%d/edge", i) ;
308 if ((fd = open (fName, O_RDONLY)) == -1) {
309 printf ("\n") ;
310 continue ;
311 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100312
joshua-yang4b08e7f2019-02-21 12:05:24 +0900313 if ((l = read (fd, buf, 16)) == 0)
314 sprintf (buf, "%s", "?") ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100315
joshua-yang4b08e7f2019-02-21 12:05:24 +0900316 buf [l] = 0 ;
317 if ((buf [strlen (buf) - 1]) == '\n')
318 buf [strlen (buf) - 1] = 0 ;
319 printf (" %-8s\n", buf) ;
320 close (fd) ;
321 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100322}
323
324
325/*
326 * doExport:
327 * gpio export pin mode
328 * This uses the /sys/class/gpio device interface.
329 *********************************************************************************
330 */
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100331void doExport (int argc, char *argv [])
332{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900333 FILE *fd ;
334 int pin ;
335 char *mode ;
336 char fName [128] ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100337
joshua-yang4b08e7f2019-02-21 12:05:24 +0900338 if (argc != 4) {
339 fprintf (stderr, "Usage: %s export pin mode\n", argv [0]) ;
340 exit (1) ;
341 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100342
joshua-yang4b08e7f2019-02-21 12:05:24 +0900343 pin = atoi (argv [2]) ;
344 mode = argv [3] ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100345
joshua-yang4b08e7f2019-02-21 12:05:24 +0900346 if ((fd = fopen ("/sys/class/gpio/export", "w")) == NULL) {
347 fprintf (stderr, "%s: Unable to open GPIO export interface: %s\n", argv [0], strerror (errno)) ;
348 exit (1) ;
349 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100350
joshua-yang4b08e7f2019-02-21 12:05:24 +0900351 fprintf (fd, "%d\n", pin) ;
352 fclose (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100353
joshua-yang4b08e7f2019-02-21 12:05:24 +0900354 sprintf (fName, "/sys/class/gpio/gpio%d/direction", pin) ;
355 if ((fd = fopen (fName, "w")) == NULL) {
356 fprintf (stderr, "%s: Unable to open GPIO direction interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
357 exit (1) ;
358 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100359
joshua-yang4b08e7f2019-02-21 12:05:24 +0900360 if ((strcasecmp (mode, "in") == 0) || (strcasecmp (mode, "input") == 0))
361 fprintf (fd, "in\n") ;
362 else if ((strcasecmp (mode, "out") == 0) || (strcasecmp (mode, "output") == 0))
363 fprintf (fd, "out\n") ;
364 else if ((strcasecmp (mode, "high") == 0) || (strcasecmp (mode, "up") == 0))
365 fprintf (fd, "high\n") ;
366 else if ((strcasecmp (mode, "low") == 0) || (strcasecmp (mode, "down") == 0))
367 fprintf (fd, "low\n") ;
368 else {
369 fprintf (stderr, "%s: Invalid mode: %s. Should be in, out, high or low\n", argv [1], mode) ;
370 exit (1) ;
371 }
372 fclose (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100373
joshua-yang4b08e7f2019-02-21 12:05:24 +0900374 // Change ownership so the current user can actually use it
375 sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
376 changeOwner (argv [0], fName) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100377
joshua-yang4b08e7f2019-02-21 12:05:24 +0900378 sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
379 changeOwner (argv [0], fName) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100380}
381
382
383/*
Gordon Hendersonda384432013-05-13 19:43:26 +0100384 * doWfi:
385 * gpio wfi pin mode
386 * Wait for Interrupt on a given pin.
387 * Slight cheat here - it's easier to actually use ISR now (which calls
388 * gpio to set the pin modes!) then we simply sleep, and expect the thread
389 * to exit the program. Crude but effective.
390 *********************************************************************************
391 */
joshua-yang4b08e7f2019-02-21 12:05:24 +0900392static void wfi (void) { exit (0) ; }
Gordon Hendersonda384432013-05-13 19:43:26 +0100393
394void doWfi (int argc, char *argv [])
395{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900396 int pin, mode ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100397
joshua-yang4b08e7f2019-02-21 12:05:24 +0900398 if (argc != 4) {
399 fprintf (stderr, "Usage: %s wfi pin mode\n", argv [0]) ;
400 exit (1) ;
401 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100402
joshua-yang4b08e7f2019-02-21 12:05:24 +0900403 pin = atoi (argv [2]) ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100404
joshua-yang4b08e7f2019-02-21 12:05:24 +0900405 if (strcasecmp (argv [3], "rising") == 0) mode = INT_EDGE_RISING ;
406 else if (strcasecmp (argv [3], "falling") == 0) mode = INT_EDGE_FALLING ;
407 else if (strcasecmp (argv [3], "both") == 0) mode = INT_EDGE_BOTH ;
408 else {
409 fprintf (stderr, "%s: wfi: Invalid mode: %s. Should be rising, falling or both\n", argv [1], argv [3]) ;
410 exit (1) ;
411 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100412
joshua-yang4b08e7f2019-02-21 12:05:24 +0900413 if (wiringPiISR (pin, mode, &wfi) < 0) {
414 fprintf (stderr, "%s: wfi: Unable to setup ISR: %s\n", argv [1], strerror (errno)) ;
415 exit (1) ;
416 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100417
joshua-yang4b08e7f2019-02-21 12:05:24 +0900418 for (;;)
419 delay (9999) ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100420}
421
422
Gordon Hendersonda384432013-05-13 19:43:26 +0100423/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100424 * doEdge:
425 * gpio edge pin mode
426 * Easy access to changing the edge trigger on a GPIO pin
427 * This uses the /sys/class/gpio device interface.
428 *********************************************************************************
429 */
430
431void doEdge (int argc, char *argv [])
432{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900433 FILE *fd ;
434 int pin ;
435 char *mode ;
436 char fName [128] ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100437
joshua-yang4b08e7f2019-02-21 12:05:24 +0900438 // Reset gpio sysfs
439 doUnexport(3, argv);
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100440
joshua-yang4b08e7f2019-02-21 12:05:24 +0900441 if (argc != 4) {
442 fprintf (stderr, "Usage: %s edge pin mode\n", argv [0]) ;
443 exit (1) ;
444 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100445
joshua-yang4b08e7f2019-02-21 12:05:24 +0900446 pin = atoi (argv [2]) ;
447 mode = argv [3] ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100448
joshua-yang4b08e7f2019-02-21 12:05:24 +0900449 // Export the pin and set direction to input
450 if ((fd = fopen ("/sys/class/gpio/export", "w")) == NULL) {
451 fprintf (stderr, "%s: Unable to open GPIO export interface: %s\n", argv [0], strerror (errno)) ;
452 exit (1) ;
453 }
454 fprintf (fd, "%d\n", pin) ;
455 fclose (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100456
joshua-yang4b08e7f2019-02-21 12:05:24 +0900457 sprintf (fName, "/sys/class/gpio/gpio%d/direction", pin) ;
458 if ((fd = fopen (fName, "w")) == NULL) {
459 fprintf (stderr, "%s: Unable to open GPIO direction interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
460 exit (1) ;
461 }
462 fprintf (fd, "in\n") ;
463 fclose (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100464
joshua-yang4b08e7f2019-02-21 12:05:24 +0900465 sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
466 if ((fd = fopen (fName, "w")) == NULL) {
467 fprintf (stderr, "%s: Unable to open GPIO edge interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
468 exit (1) ;
469 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100470
joshua-yang4b08e7f2019-02-21 12:05:24 +0900471 if (strcasecmp (mode, "none") == 0) fprintf (fd, "none\n") ;
472 else if (strcasecmp (mode, "rising") == 0) fprintf (fd, "rising\n") ;
473 else if (strcasecmp (mode, "falling") == 0) fprintf (fd, "falling\n") ;
474 else if (strcasecmp (mode, "both") == 0) fprintf (fd, "both\n") ;
475 else {
476 fprintf (stderr, "%s: Invalid mode: %s. Should be none, rising, falling or both\n", argv [1], mode) ;
477 exit (1) ;
478 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100479
joshua-yang4b08e7f2019-02-21 12:05:24 +0900480 // Change ownership of the value and edge files, so the current user can actually use it!
481 sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
482 changeOwner (argv [0], fName) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100483
joshua-yang4b08e7f2019-02-21 12:05:24 +0900484 sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
485 changeOwner (argv [0], fName) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100486
joshua-yang4b08e7f2019-02-21 12:05:24 +0900487 fclose (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100488}
489
490
491/*
492 * doUnexport:
493 * gpio unexport pin
494 * This uses the /sys/class/gpio device interface.
495 *********************************************************************************
496 */
497
498void doUnexport (int argc, char *argv [])
499{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900500 FILE *fd ;
501 int pin ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100502
joshua-yang4b08e7f2019-02-21 12:05:24 +0900503 if (argc != 3) {
504 fprintf (stderr, "Usage: %s unexport pin\n", argv [0]) ;
505 exit (1) ;
506 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100507
joshua-yang4b08e7f2019-02-21 12:05:24 +0900508 pin = atoi (argv [2]) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100509
joshua-yang4b08e7f2019-02-21 12:05:24 +0900510 if ((fd = fopen ("/sys/class/gpio/unexport", "w")) == NULL) {
511 fprintf (stderr, "%s: Unable to open GPIO export interface\n", argv [0]) ;
512 exit (1) ;
513 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100514
joshua-yang4b08e7f2019-02-21 12:05:24 +0900515 fprintf (fd, "%d\n", pin) ;
516 fclose (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100517}
518
519
520/*
521 * doUnexportAll:
522 * gpio unexportall
523 * Un-Export all the GPIO pins.
524 * This uses the /sys/class/gpio device interface.
525 *********************************************************************************
526 */
527
Gordon Hendersonda384432013-05-13 19:43:26 +0100528void doUnexportall (char *progName)
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100529{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900530 FILE *fd ;
531 int pin ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100532
joshua-yang4b08e7f2019-02-21 12:05:24 +0900533 for (pin = 0 ; pin < 256 ; ++pin) {
534 if ((fd = fopen ("/sys/class/gpio/unexport", "w")) == NULL) {
535 fprintf (stderr, "%s: Unable to open GPIO export interface\n", progName) ;
536 exit (1) ;
537 }
538 fprintf (fd, "%d\n", pin) ;
539 fclose (fd) ;
540 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100541}
542
Gordon Hendersonda384432013-05-13 19:43:26 +0100543/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100544 * doMode:
545 * gpio mode pin mode ...
546 *********************************************************************************
547 */
548
549void doMode (int argc, char *argv [])
550{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900551 int pin ;
552 char *mode ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100553
joshua-yang4b08e7f2019-02-21 12:05:24 +0900554 if (argc != 4) {
555 fprintf (stderr, "Usage: %s mode pin mode\n", argv [0]) ;
556 exit (1) ;
557 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100558
joshua-yang4b08e7f2019-02-21 12:05:24 +0900559 pin = atoi (argv [2]) ;
560 mode = argv [3] ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100561
joshua-yang4b08e7f2019-02-21 12:05:24 +0900562 if (strcasecmp (mode, "in") == 0) pinMode (pin, INPUT) ;
563 else if (strcasecmp (mode, "input") == 0) pinMode (pin, INPUT) ;
564 else if (strcasecmp (mode, "out") == 0) pinMode (pin, OUTPUT) ;
565 else if (strcasecmp (mode, "output") == 0) pinMode (pin, OUTPUT) ;
566 else if (strcasecmp (mode, "pwm") == 0) pinMode (pin, PWM_OUTPUT) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900567 else if (strcasecmp (mode, "up") == 0) pullUpDnControl (pin, PUD_UP) ;
568 else if (strcasecmp (mode, "down") == 0) pullUpDnControl (pin, PUD_DOWN) ;
569 else if (strcasecmp (mode, "tri") == 0) pullUpDnControl (pin, PUD_OFF) ;
570 else if (strcasecmp (mode, "off") == 0) pullUpDnControl (pin, PUD_OFF) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900571 else {
572 fprintf (stderr, "%s: Invalid mode: %s. Should be in/out/pwm/clock/up/down/tri\n", argv [1], mode) ;
573 exit (1) ;
574 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100575}
576
577
578/*
Deokgyu Yanga0bd5eb2020-03-20 11:16:06 +0900579 * doDrive:
joshua-yang4b08e7f2019-02-21 12:05:24 +0900580 * gpio drive pin value for ODROIDs since it depends on the SoC
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100581 *********************************************************************************
582 */
583
Deokgyu Yanga0bd5eb2020-03-20 11:16:06 +0900584static void doDrive (int argc, char *argv [])
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100585{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900586 int pin, val;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100587
joshua-yang4b08e7f2019-02-21 12:05:24 +0900588 if (argc != 4) {
589 fprintf (stderr, "Usage: %s drive pin value\n", argv [0]) ;
590 exit (1) ;
591 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100592
joshua-yang4b08e7f2019-02-21 12:05:24 +0900593 pin = atoi (argv [2]) ;
594 val = atoi (argv [3]) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100595
Deokgyu Yanga0bd5eb2020-03-20 11:16:06 +0900596 setDrive (pin, val) ;
Gordon Hendersondf453882014-07-17 22:23:57 +0100597}
598
Gordon Henderson99095e32012-08-27 20:56:14 +0100599/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100600 * doWrite:
601 * gpio write pin value
602 *********************************************************************************
603 */
604
Gordon Henderson1bb49892012-08-19 15:33:26 +0100605static void doWrite (int argc, char *argv [])
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100606{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900607 int pin, val ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100608
joshua-yang4b08e7f2019-02-21 12:05:24 +0900609 if (argc != 4) {
610 fprintf (stderr, "Usage: %s write pin value\n", argv [0]) ;
611 exit (1) ;
612 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100613
joshua-yang4b08e7f2019-02-21 12:05:24 +0900614 pin = atoi (argv [2]) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100615
joshua-yang4b08e7f2019-02-21 12:05:24 +0900616 if ((strcasecmp (argv [3], "up") == 0) || (strcasecmp (argv [3], "on") == 0))
617 val = 1 ;
618 else if ((strcasecmp (argv [3], "down") == 0) || (strcasecmp (argv [3], "off") == 0))
619 val = 0 ;
620 else
621 val = atoi (argv [3]) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100622
joshua-yang4b08e7f2019-02-21 12:05:24 +0900623 if (val == 0)
624 digitalWrite (pin, LOW) ;
625 else
626 digitalWrite (pin, HIGH) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100627}
628
Gordon Henderson25e4ec52012-12-06 21:49:41 +0000629/*
630 * doWriteByte:
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000631 * gpio wb value
Gordon Henderson25e4ec52012-12-06 21:49:41 +0000632 *********************************************************************************
633 */
634
635static void doWriteByte (int argc, char *argv [])
636{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900637 int val ;
Gordon Henderson25e4ec52012-12-06 21:49:41 +0000638
joshua-yang4b08e7f2019-02-21 12:05:24 +0900639 if (argc != 3) {
640 fprintf (stderr, "Usage: %s wb value\n", argv [0]) ;
641 exit (1) ;
642 }
643 val = (int)strtol (argv [2], NULL, 0) ;
Gordon Henderson25e4ec52012-12-06 21:49:41 +0000644
joshua-yang4b08e7f2019-02-21 12:05:24 +0900645 digitalWriteByte (val) ;
Gordon Henderson25e4ec52012-12-06 21:49:41 +0000646}
647
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100648
649/*
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000650 * doReadByte:
651 * gpio rbx|rbd value
652 *********************************************************************************
653 */
654
655static void doReadByte (int argc, char *argv [], int printHex)
656{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900657 int val ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000658
joshua-yang4b08e7f2019-02-21 12:05:24 +0900659 if (argc != 2) {
660 fprintf (stderr, "Usage: %s rbx|rbd\n", argv [0]) ;
661 exit (1) ;
662 }
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000663
joshua-yang4b08e7f2019-02-21 12:05:24 +0900664 val = digitalReadByte () ;
665 if (printHex)
666 printf ("%02X\n", val) ;
667 else
668 printf ("%d\n", val) ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000669}
670
671
672/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100673 * doRead:
674 * Read a pin and return the value
675 *********************************************************************************
676 */
677
Joshua Yang6e7a6e62019-07-09 15:57:26 +0900678void doRead (int argc, char *argv [])
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100679{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900680 int pin, val ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100681
joshua-yang4b08e7f2019-02-21 12:05:24 +0900682 if (argc != 3) {
683 fprintf (stderr, "Usage: %s read pin\n", argv [0]) ;
684 exit (1) ;
685 }
686 pin = atoi (argv [2]) ;
687 val = digitalRead (pin) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100688
joshua-yang4b08e7f2019-02-21 12:05:24 +0900689 printf ("%s\n", val == 0 ? "0" : "1") ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100690}
691
692
693/*
Gordon Hendersonda384432013-05-13 19:43:26 +0100694 * doAread:
695 * Read an analog pin and return the value
696 *********************************************************************************
697 */
698
Joshua Yang6e7a6e62019-07-09 15:57:26 +0900699void doAread (int argc, char *argv [])
Gordon Hendersonda384432013-05-13 19:43:26 +0100700{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900701 if (argc != 3) {
702 fprintf (stderr, "Usage: %s aread pin\n", argv [0]) ;
703 exit (1) ;
704 }
705 printf ("%d\n", analogRead (atoi (argv [2]))) ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100706}
707
708
709/*
710 * doToggle:
711 * Toggle an IO pin
712 *********************************************************************************
713 */
714
715void doToggle (int argc, char *argv [])
716{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900717 int pin ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100718
joshua-yang4b08e7f2019-02-21 12:05:24 +0900719 if (argc != 3) {
720 fprintf (stderr, "Usage: %s toggle pin\n", argv [0]) ;
721 exit (1) ;
722 }
723 pin = atoi (argv [2]) ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100724
joshua-yang4b08e7f2019-02-21 12:05:24 +0900725 digitalWrite (pin, !digitalRead (pin)) ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100726}
727
Gordon Hendersondca8a192014-07-14 08:39:38 +0100728
729/*
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000730 * doBlink:
731 * Blink an IO pin
732 *********************************************************************************
733 */
734
735void doBlink (int argc, char *argv [])
736{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900737 int pin ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000738
joshua-yang4b08e7f2019-02-21 12:05:24 +0900739 if (argc != 3) {
740 fprintf (stderr, "Usage: %s blink pin\n", argv [0]) ;
741 exit (1) ;
742 }
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000743
joshua-yang4b08e7f2019-02-21 12:05:24 +0900744 pin = atoi (argv [2]) ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000745
joshua-yang4b08e7f2019-02-21 12:05:24 +0900746 pinMode (pin, OUTPUT) ;
747 for (;;) {
748 digitalWrite (pin, !digitalRead (pin)) ;
749 delay (500) ;
750 }
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000751}
752
Gordon Henderson56c77b52013-02-01 20:19:22 +0000753/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100754 * doPwm:
755 * Output a PWM value on a pin
756 *********************************************************************************
757 */
758
759void doPwm (int argc, char *argv [])
760{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900761 int pin, val ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100762
joshua-yang4b08e7f2019-02-21 12:05:24 +0900763 if (argc != 4) {
764 fprintf (stderr, "Usage: %s pwm <pin> <value>\n", argv [0]) ;
765 exit (1) ;
766 }
767 pin = atoi (argv [2]) ;
768 val = atoi (argv [3]) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100769
joshua-yang4b08e7f2019-02-21 12:05:24 +0900770 pwmWrite (pin, val) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100771}
772
773
774/*
Deokgyu Yanga0bd5eb2020-03-20 11:16:06 +0900775 * doPwmRange: doPwmClock:
Gordon Henderson8cb49392012-09-16 10:15:32 +0100776 * Change the PWM mode, range and clock divider values
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100777 *********************************************************************************
778 */
779
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900780static void doPwmRange (int argc, char *argv [])
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100781{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900782 unsigned int range ;
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100783
joshua-yang4b08e7f2019-02-21 12:05:24 +0900784 if (argc != 3) {
785 fprintf (stderr, "Usage: %s pwmr <range>\n", argv [0]) ;
786 exit (1) ;
787 }
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100788
joshua-yang4b08e7f2019-02-21 12:05:24 +0900789 range = (unsigned int)strtoul (argv [2], NULL, 10) ;
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100790
joshua-yang4b08e7f2019-02-21 12:05:24 +0900791 if (range == 0) {
792 fprintf (stderr, "%s: range must be > 0\n", argv [0]) ;
793 exit (1) ;
794 }
795 pwmSetRange (range) ;
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100796}
797
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900798static void doPwmClock (int argc, char *argv [])
Gordon Henderson8cb49392012-09-16 10:15:32 +0100799{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900800 unsigned int clock ;
Gordon Henderson8cb49392012-09-16 10:15:32 +0100801
joshua-yang4b08e7f2019-02-21 12:05:24 +0900802 if (argc != 3) {
803 fprintf (stderr, "Usage: %s pwmc <clock>\n", argv [0]) ;
804 exit (1) ;
805 }
Gordon Henderson8cb49392012-09-16 10:15:32 +0100806
joshua-yang4b08e7f2019-02-21 12:05:24 +0900807 clock = (unsigned int)strtoul (argv [2], NULL, 10) ;
Gordon Henderson8cb49392012-09-16 10:15:32 +0100808
joshua-yang4b08e7f2019-02-21 12:05:24 +0900809 if ((clock < 1) || (clock > 4095)) {
810 fprintf (stderr, "%s: clock must be between 0 and 4096\n", argv [0]) ;
811 exit (1) ;
812 }
813 pwmSetClock (clock) ;
Gordon Henderson8cb49392012-09-16 10:15:32 +0100814}
815
joshua-yang4b08e7f2019-02-21 12:05:24 +0900816/*
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000817 * doVersion:
Gordon Hendersonb0a60c32016-02-29 06:57:38 +0000818 * Handle the ever more complicated version command and print out
819 * some usefull information.
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000820 *********************************************************************************
821 */
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000822static void doVersion (char *argv [])
823{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900824 int model, rev, mem, maker, warranty ;
825 struct stat statBuf ;
826 char name [80] ;
827 FILE *fd ;
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000828
Joshua Yang41a423e2019-07-16 18:08:16 +0900829 int vMaj;
830 char *vMin[32];
Gordon Hendersone687f3f2017-01-24 12:13:39 +0000831
Joshua Yang41a423e2019-07-16 18:08:16 +0900832 wiringPiVersion (&vMaj, vMin) ;
833 printf ("gpio version: %d.%s\n", vMaj, *vMin) ;
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900834 printf ("Copyright (c) 2012-2017 Gordon Henderson, 2017-2020 Hardkernel Co., Ltd.\n") ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900835 printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ;
836 printf ("For details type: %s -warranty\n", argv [0]) ;
837 printf ("\n") ;
838 piBoardId (&model, &rev, &mem, &maker, &warranty) ;
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000839
joshua-yang4b08e7f2019-02-21 12:05:24 +0900840 printf ("ODROID Board Details:\n") ;
841 printf (" Type: %s, Revision: %s, Memory: %dMB\n" \
Joshua Yang6e7a6e62019-07-09 15:57:26 +0900842 " Maker: %s, Chip-Vendor: %s\n",
joshua-yang4b08e7f2019-02-21 12:05:24 +0900843 piModelNames [model],
844 piRevisionNames [rev],
845 piMemorySize [mem],
846 "Hardkernel",
847 piMakerNames [maker]);
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000848
Deokgyu Yang26f88152020-08-20 12:09:29 +0900849 // Show current kernel version
Deokgyu Yang858c8142020-08-25 17:13:34 +0900850 printf(" * Current devices' kernel version: %s\n", kernelVersion->release);
Deokgyu Yang26f88152020-08-20 12:09:29 +0900851
joshua-yang4b08e7f2019-02-21 12:05:24 +0900852 // Check for device tree
853 if (stat ("/proc/device-tree", &statBuf) == 0) // We're on a devtree system ...
854 printf (" * Device tree is enabled.\n") ;
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000855
joshua-yang4b08e7f2019-02-21 12:05:24 +0900856 // Output Kernel idea of board type
857 if (stat ("/proc/device-tree/model", &statBuf) == 0) {
858 if ((fd = fopen ("/proc/device-tree/model", "r")) != NULL) {
Joshua Yang6e7a6e62019-07-09 15:57:26 +0900859 if (fgets (name, 80, fd) == NULL)
860 fprintf(stderr, "Unable to read from the file descriptor: %s \n", strerror(errno));
joshua-yang4b08e7f2019-02-21 12:05:24 +0900861 fclose (fd) ;
862 printf (" *--> %s\n", name) ;
863 }
864 }
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000865
joshua-yang4b08e7f2019-02-21 12:05:24 +0900866 // User level GPIO is GO
867 if (stat ("/dev/gpiomem", &statBuf) == 0)
868 printf (" * Supports user-level GPIO access.\n") ;
869 else
870 printf (" * Root or sudo required for GPIO access.\n") ;
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000871}
872
873
874/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100875 * main:
876 * Start here
877 *********************************************************************************
878 */
879
880int main (int argc, char *argv [])
881{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900882 int i ;
Yang Deokgyu020ff312019-09-11 11:43:05 +0900883 struct stat statBuf ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100884
joshua-yang4b08e7f2019-02-21 12:05:24 +0900885 if (getenv ("WIRINGPI_DEBUG") != NULL) {
886 printf ("gpio: wiringPi debug mode enabled\n") ;
887 wiringPiDebug = TRUE ;
888 }
Gordon Henderson13bbba72013-01-14 11:31:56 +0000889
joshua-yang4b08e7f2019-02-21 12:05:24 +0900890 if (argc == 1) {
891 fprintf (stderr, "%s\n", usage) ;
892 return 1 ;
893 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100894
joshua-yang4b08e7f2019-02-21 12:05:24 +0900895 // Help
896 if (strcasecmp (argv [1], "-h") == 0) {
897 printf ("%s: %s\n", argv [0], usage) ;
898 return 0 ;
899 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100900
joshua-yang4b08e7f2019-02-21 12:05:24 +0900901 // Version & Warranty
902 // Wish I could remember why I have both -R and -V ...
903 if ((strcmp (argv [1], "-R") == 0) || (strcmp (argv [1], "-V") == 0)) {
904 printf ("%d\n", piGpioLayout ()) ;
905 return 0 ;
906 }
Gordon Henderson178ea082012-08-19 15:17:03 +0100907
joshua-yang4b08e7f2019-02-21 12:05:24 +0900908 // Version and information
909 if (strcmp (argv [1], "-v") == 0) {
910 doVersion (argv) ;
911 return 0 ;
912 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100913
joshua-yang4b08e7f2019-02-21 12:05:24 +0900914 if (strcasecmp (argv [1], "-warranty") == 0) {
915 printf ("gpio version: %s\n", VERSION) ;
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900916 printf ("Copyright (c) 2012-2017 Gordon Henderson, 2017-2020 Hardkernel Co., Ltd.\n") ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900917 printf ("\n") ;
918 printf (" This program is free software; you can redistribute it and/or modify\n") ;
919 printf (" it under the terms of the GNU Leser General Public License as published\n") ;
920 printf (" by the Free Software Foundation, either version 3 of the License, or\n") ;
921 printf (" (at your option) any later version.\n") ;
922 printf ("\n") ;
923 printf (" This program is distributed in the hope that it will be useful,\n") ;
924 printf (" but WITHOUT ANY WARRANTY; without even the implied warranty of\n") ;
925 printf (" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n") ;
926 printf (" GNU Lesser General Public License for more details.\n") ;
927 printf ("\n") ;
928 printf (" You should have received a copy of the GNU Lesser General Public License\n") ;
929 printf (" along with this program. If not, see <http://www.gnu.org/licenses/>.\n") ;
930 printf ("\n") ;
931 return 0 ;
932 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100933
Yang Deokgyu020ff312019-09-11 11:43:05 +0900934 if (geteuid () != 0 && stat("/dev/gpiomem", &statBuf) != 0) {
joshua-yang4b08e7f2019-02-21 12:05:24 +0900935 fprintf (stderr, "%s: Must be root to run. Program should be suid root. This is an error.\n", argv [0]) ;
936 return 1 ;
937 }
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000938
joshua-yang4b08e7f2019-02-21 12:05:24 +0900939 // Initial test for /sys/class/gpio operations:
940 if (strcasecmp (argv [1], "exports" ) == 0) { doExports (argc, argv) ; return 0 ; }
941 else if (strcasecmp (argv [1], "export" ) == 0) { doExport (argc, argv) ; return 0 ; }
942 else if (strcasecmp (argv [1], "edge" ) == 0) { doEdge (argc, argv) ; return 0 ; }
943 else if (strcasecmp (argv [1], "unexport" ) == 0) { doUnexport (argc, argv) ; return 0 ; }
944 else if (strcasecmp (argv [1], "unexportall") == 0) { doUnexportall (argv [0]) ; return 0 ; }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100945
joshua-yang4b08e7f2019-02-21 12:05:24 +0900946 // Check for load command:
947 if (strcasecmp (argv [1], "load" ) == 0) { doLoad (argc, argv) ; return 0 ; }
948 if (strcasecmp (argv [1], "unload" ) == 0) { doUnLoad (argc, argv) ; return 0 ; }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100949
joshua-yang4b08e7f2019-02-21 12:05:24 +0900950 // Check for allreadall command, force Gpio mode
951 if (strcasecmp (argv [1], "allreadall") == 0) {
952 wiringPiSetupGpio () ;
953 doAllReadall () ;
954 return 0 ;
955 }
Gordon Henderson178ea082012-08-19 15:17:03 +0100956
joshua-yang4b08e7f2019-02-21 12:05:24 +0900957 if (strcasecmp (argv [1], "-g") == 0) { // Check for -g argument
958 wiringPiSetupGpio () ;
Gordon Henderson178ea082012-08-19 15:17:03 +0100959
joshua-yang4b08e7f2019-02-21 12:05:24 +0900960 for (i = 2 ; i < argc ; ++i)
961 argv [i - 1] = argv [i] ;
962 --argc ;
963 wpMode = MODE_GPIO ;
964 } else if (strcasecmp (argv [1], "-1") == 0) { // Check for -1 argument
965 wiringPiSetupPhys () ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100966
joshua-yang4b08e7f2019-02-21 12:05:24 +0900967 for (i = 2 ; i < argc ; ++i)
968 argv [i - 1] = argv [i] ;
969 --argc ;
970 wpMode = MODE_PHYS ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900971 } else if (strcasecmp (argv [1], "-z") == 0) { // Check for -z argument so we don't actually initialise wiringPi
972 for (i = 2 ; i < argc ; ++i)
973 argv [i - 1] = argv [i] ;
974 --argc ;
975 wpMode = MODE_UNINITIALISED ;
976 } else { // Default to wiringPi mode
977 wiringPiSetup () ;
978 wpMode = MODE_PINS ;
979 }
Gordon Hendersonb0a60c32016-02-29 06:57:38 +0000980
joshua-yang4b08e7f2019-02-21 12:05:24 +0900981 if (argc <= 1) {
982 fprintf (stderr, "%s: no command given\n", argv [0]) ;
983 exit (EXIT_FAILURE) ;
984 }
Gordon Hendersonb0a60c32016-02-29 06:57:38 +0000985
joshua-yang4b08e7f2019-02-21 12:05:24 +0900986 // Core wiringPi functions
987 /**/ if (strcasecmp (argv [1], "mode" ) == 0) doMode (argc, argv) ;
988 else if (strcasecmp (argv [1], "read" ) == 0) doRead (argc, argv) ;
989 else if (strcasecmp (argv [1], "write" ) == 0) doWrite (argc, argv) ;
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900990 else if (strcasecmp (argv [1], "pwm" ) == 0) doPwm (argc, argv) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900991 else if (strcasecmp (argv [1], "aread" ) == 0) doAread (argc, argv) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100992
joshua-yang4b08e7f2019-02-21 12:05:24 +0900993 // GPIO Nicies
994 else if (strcasecmp (argv [1], "toggle" ) == 0) doToggle (argc, argv) ;
995 else if (strcasecmp (argv [1], "blink" ) == 0) doBlink (argc, argv) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100996
joshua-yang4b08e7f2019-02-21 12:05:24 +0900997 // Pi Specifics
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900998 else if (strcasecmp (argv [1], "pwmr" ) == 0) doPwmRange (argc, argv) ;
999 else if (strcasecmp (argv [1], "pwmc" ) == 0) doPwmClock (argc, argv) ;
Deokgyu Yanga0bd5eb2020-03-20 11:16:06 +09001000 else if (strcasecmp (argv [1], "drive" ) == 0) doDrive (argc, argv) ;
Yang Deokgyu5106f2a2019-09-20 12:27:57 +09001001 else if (strcasecmp (argv [1], "readall" ) == 0) doReadall (argc, argv) ;
1002 else if (strcasecmp (argv [1], "nreadall" ) == 0) doReadall (argc, argv) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +09001003 else if (strcasecmp (argv [1], "i2cdetect") == 0) doI2Cdetect (argc, argv) ;
1004 else if (strcasecmp (argv [1], "i2cd" ) == 0) doI2Cdetect (argc, argv) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +09001005 else if (strcasecmp (argv [1], "wb" ) == 0) doWriteByte (argc, argv) ;
1006 else if (strcasecmp (argv [1], "rbx" ) == 0) doReadByte (argc, argv, TRUE) ;
1007 else if (strcasecmp (argv [1], "rbd" ) == 0) doReadByte (argc, argv, FALSE) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +09001008 else if (strcasecmp (argv [1], "wfi" ) == 0) doWfi (argc, argv) ;
1009 else {
1010 fprintf (stderr, "%s: Unknown command: %s.\n", argv [0], argv [1]) ;
1011 exit (EXIT_FAILURE) ;
1012 }
1013 return 0 ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +01001014}