blob: aa1ec1bc20ee7acfc31da5fd4113bb80ec10cccb [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"
70 " gpio pwm-bal/pwm-ms \n"
71 " gpio pwmr <range> \n"
72 " gpio pwmc <divider> \n"
73 " gpio load spi/i2c\n"
74 " gpio unload spi/i2c\n"
75 " gpio i2cd/i2cdetect\n"
76 " gpio rbx/rbd\n"
Deokgyu Yang89cf23c2020-03-19 17:21:21 +090077 " gpio wb <value>\n";
Gordon Hendersonbf0ad862012-08-16 15:04:43 +010078
79
Gordon Henderson6fba4032014-06-24 19:23:31 +010080#ifdef NOT_FOR_NOW
Gordon Hendersonbf0ad862012-08-16 15:04:43 +010081/*
Gordon Hendersonf18c8f72013-08-03 23:53:35 +010082 * decodePin:
83 * Decode a pin "number" which can actually be a pin name to represent
84 * one of the Pi's on-board pins.
85 *********************************************************************************
86 */
Gordon Hendersonf18c8f72013-08-03 23:53:35 +010087static int decodePin (const char *str)
88{
joshua-yang4b08e7f2019-02-21 12:05:24 +090089 // The first case - see if it's a number:
90 if (isdigit (str [0]))
91 return atoi (str) ;
Gordon Hendersonf18c8f72013-08-03 23:53:35 +010092
joshua-yang4b08e7f2019-02-21 12:05:24 +090093 return 0 ;
Gordon Hendersonf18c8f72013-08-03 23:53:35 +010094}
Gordon Henderson6fba4032014-06-24 19:23:31 +010095#endif
Gordon Hendersonf18c8f72013-08-03 23:53:35 +010096
97
98/*
Gordon Hendersonb1dfc182016-12-12 14:19:55 +000099 * findExecutable:
100 * Code to locate the path to the given executable. We have a fixed list
101 * of locations to try which completely overrides any $PATH environment.
102 * This may be detrimental, however it avoids the reliance on $PATH
103 * which may be a security issue when this program is run a set-uid-root.
104 *********************************************************************************
105 */
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000106static const char *searchPath [] =
107{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900108 "/sbin",
109 "/usr/sbin",
110 "/bin",
111 "/usr/bin",
112 NULL,
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000113} ;
114
115static char *findExecutable (const char *progName)
116{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900117 static char *path = NULL ;
118 int len = strlen (progName) ;
119 int i = 0 ;
120 struct stat statBuf ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000121
joshua-yang4b08e7f2019-02-21 12:05:24 +0900122 for (i = 0 ; searchPath [i] != NULL ; ++i) {
123 path = malloc (strlen (searchPath [i]) + len + 2) ;
124 sprintf (path, "%s/%s", searchPath [i], progName) ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000125
joshua-yang4b08e7f2019-02-21 12:05:24 +0900126 if (stat (path, &statBuf) == 0)
127 return path ;
128 free (path) ;
129 }
130 return NULL ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000131}
132
133
134/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100135 * changeOwner:
136 * Change the ownership of the file to the real userId of the calling
137 * program so we can access it.
138 *********************************************************************************
139 */
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100140static void changeOwner (char *cmd, char *file)
141{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900142 uid_t uid = getuid () ;
143 uid_t gid = getgid () ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100144
joshua-yang4b08e7f2019-02-21 12:05:24 +0900145 if (chown (file, uid, gid) != 0) {
146 // Removed (ignoring) the check for not existing as I'm fed-up with morons telling me that
147 // the warning message is an error.
148 if (errno != ENOENT)
149 fprintf (stderr, "%s: Unable to change ownership of %s: %s\n",
150 cmd, file, strerror (errno)) ;
151 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100152}
153
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100154/*
155 * doLoad:
156 * Load either the spi or i2c modules and change device ownerships, etc.
157 *********************************************************************************
158 */
Gordon Hendersonf6c40cb2015-09-24 22:35:31 +0100159static void checkDevTree (char *argv [])
160{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900161 struct stat statBuf ;
Gordon Hendersonf6c40cb2015-09-24 22:35:31 +0100162
joshua-yang4b08e7f2019-02-21 12:05:24 +0900163 // We're on a devtree system ...
164 if (stat ("/proc/device-tree", &statBuf) == 0) {
165 fprintf (stderr,
166 "%s: Unable to load/unload modules as this kernel has the device tree enabled.\n"
167 " You need to edit /etc/modprobe.d/blacklist-odroid.conf or update /media/models.dts file.\n"
168 " If you want to use SPI, you should find out spidev module line at the blacklist-odroid.conf\n"
169 " and uncomment that. Then reboot to enable the module.\n\n"
170 " Please refer to our wiki page:\n"
171 " https://wiki.odroid.com/start\n", argv [0]) ;
172 exit (1) ;
173 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100174}
175
Luke Go2ee8a0d2019-07-08 15:37:07 +0900176static void doLoad (int UNU argc, char *argv [])
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100177{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900178 checkDevTree (argv) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100179}
180
181
Gordon Henderson183c5a62012-10-21 15:25:16 +0100182/*
Gordon Hendersoneb1fc2c2015-01-30 18:14:49 +0000183 * doUnLoad:
184 * Un-Load either the spi or i2c modules and change device ownerships, etc.
185 *********************************************************************************
186 */
Luke Go2ee8a0d2019-07-08 15:37:07 +0900187static void doUnLoad (int UNU argc, char *argv [])
Gordon Hendersoneb1fc2c2015-01-30 18:14:49 +0000188{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900189 checkDevTree (argv) ;
Gordon Hendersoneb1fc2c2015-01-30 18:14:49 +0000190}
191
192
193/*
Gordon Hendersonda384432013-05-13 19:43:26 +0100194 * doI2Cdetect:
195 * Run the i2cdetect command with the right runes for this Pi revision
196 *********************************************************************************
197 */
Gordon Hendersone687f3f2017-01-24 12:13:39 +0000198static void doI2Cdetect (UNU int argc, char *argv [])
Gordon Hendersonda384432013-05-13 19:43:26 +0100199{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900200 int model, rev, mem, maker, overVolted, port;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900201 char *c, *command ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100202
joshua-yang4b08e7f2019-02-21 12:05:24 +0900203 piBoardId(&model, &rev, &mem, &maker, &overVolted);
Gordon Hendersonda384432013-05-13 19:43:26 +0100204
joshua-yang4b08e7f2019-02-21 12:05:24 +0900205 switch (model) {
206 case MODEL_ODROID_C1: case MODEL_ODROID_C2:
207 case MODEL_ODROID_XU3:
joshua-yang4b08e7f2019-02-21 12:05:24 +0900208 port = 1;
209 break;
210 case MODEL_ODROID_N1:
joshua-yang4b08e7f2019-02-21 12:05:24 +0900211 port = 4;
212 break;
213 case MODEL_ODROID_N2:
joshua-yang4b08e7f2019-02-21 12:05:24 +0900214 port = 3;
Joshua Yang964b4222019-07-09 16:00:28 +0900215 break;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900216 default:
217 break;
218 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100219
joshua-yang4b08e7f2019-02-21 12:05:24 +0900220 if ((c = findExecutable (I2CDETECT)) == NULL) {
221 fprintf (stderr, "%s: Unable to find i2cdetect command: %s\n", argv [0], strerror (errno)) ;
222 return ;
223 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100224
Joshua Yang964b4222019-07-09 16:00:28 +0900225 switch (model) {
226 case MODEL_ODROID_C1:
227 case MODEL_ODROID_C2:
joshua-yang4b08e7f2019-02-21 12:05:24 +0900228 if (!moduleLoaded (AML_MODULE_I2C)) {
229 fprintf (stderr, "%s: The I2C kernel module(s) are not loaded.\n", argv [0]) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900230 }
Joshua Yang964b4222019-07-09 16:00:28 +0900231 break;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900232 default:
233 break;
234 }
235
236 command = malloc (strlen (c) + 16) ;
237 sprintf (command, "%s -y %d", c, port) ;
238 if (system (command) < 0)
239 fprintf (stderr, "%s: Unable to run i2cdetect: %s\n", argv [0], strerror (errno)) ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100240}
241
242
243/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100244 * doExports:
245 * List all GPIO exports
246 *********************************************************************************
247 */
Gordon Hendersone687f3f2017-01-24 12:13:39 +0000248static void doExports (UNU int argc, UNU char *argv [])
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100249{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900250 int fd ;
251 int i, l, first ;
252 char fName [128] ;
253 char buf [16] ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100254
joshua-yang4b08e7f2019-02-21 12:05:24 +0900255 // Crude, but effective
256 for (first = 0, i = 0 ; i < 256 ; ++i) {
257 // Try to read the direction
258 sprintf (fName, "/sys/class/gpio/gpio%d/direction", i) ;
259 if ((fd = open (fName, O_RDONLY)) == -1)
260 continue ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100261
joshua-yang4b08e7f2019-02-21 12:05:24 +0900262 if (first == 0) {
263 ++first ;
264 printf ("GPIO Pins exported:\n") ;
265 }
266 printf ("%4d: ", i) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100267
joshua-yang4b08e7f2019-02-21 12:05:24 +0900268 if ((l = read (fd, buf, 16)) == 0)
269 sprintf (buf, "%s", "?") ;
Joshua Yang6e7a6e62019-07-09 15:57:26 +0900270
joshua-yang4b08e7f2019-02-21 12:05:24 +0900271 buf [l] = 0 ;
272 if ((buf [strlen (buf) - 1]) == '\n')
273 buf [strlen (buf) - 1] = 0 ;
274 printf ("%-3s", buf) ;
275 close (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100276
joshua-yang4b08e7f2019-02-21 12:05:24 +0900277 // Try to Read the value
278 sprintf (fName, "/sys/class/gpio/gpio%d/value", i) ;
279 if ((fd = open (fName, O_RDONLY)) == -1) {
280 printf ("No Value file (huh?)\n") ;
281 continue ;
282 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100283
joshua-yang4b08e7f2019-02-21 12:05:24 +0900284 if ((l = read (fd, buf, 16)) == 0)
285 sprintf (buf, "%s", "?") ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100286
joshua-yang4b08e7f2019-02-21 12:05:24 +0900287 buf [l] = 0 ;
288 if ((buf [strlen (buf) - 1]) == '\n')
289 buf [strlen (buf) - 1] = 0 ;
290 printf (" %s", buf) ;
291 close (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100292
joshua-yang4b08e7f2019-02-21 12:05:24 +0900293 // Read any edge trigger file
294 sprintf (fName, "/sys/class/gpio/gpio%d/edge", i) ;
295 if ((fd = open (fName, O_RDONLY)) == -1) {
296 printf ("\n") ;
297 continue ;
298 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100299
joshua-yang4b08e7f2019-02-21 12:05:24 +0900300 if ((l = read (fd, buf, 16)) == 0)
301 sprintf (buf, "%s", "?") ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100302
joshua-yang4b08e7f2019-02-21 12:05:24 +0900303 buf [l] = 0 ;
304 if ((buf [strlen (buf) - 1]) == '\n')
305 buf [strlen (buf) - 1] = 0 ;
306 printf (" %-8s\n", buf) ;
307 close (fd) ;
308 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100309}
310
311
312/*
313 * doExport:
314 * gpio export pin mode
315 * This uses the /sys/class/gpio device interface.
316 *********************************************************************************
317 */
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100318void doExport (int argc, char *argv [])
319{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900320 FILE *fd ;
321 int pin ;
322 char *mode ;
323 char fName [128] ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100324
joshua-yang4b08e7f2019-02-21 12:05:24 +0900325 if (argc != 4) {
326 fprintf (stderr, "Usage: %s export pin mode\n", argv [0]) ;
327 exit (1) ;
328 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100329
joshua-yang4b08e7f2019-02-21 12:05:24 +0900330 pin = atoi (argv [2]) ;
331 mode = argv [3] ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100332
joshua-yang4b08e7f2019-02-21 12:05:24 +0900333 if ((fd = fopen ("/sys/class/gpio/export", "w")) == NULL) {
334 fprintf (stderr, "%s: Unable to open GPIO export interface: %s\n", argv [0], strerror (errno)) ;
335 exit (1) ;
336 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100337
joshua-yang4b08e7f2019-02-21 12:05:24 +0900338 fprintf (fd, "%d\n", pin) ;
339 fclose (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100340
joshua-yang4b08e7f2019-02-21 12:05:24 +0900341 sprintf (fName, "/sys/class/gpio/gpio%d/direction", pin) ;
342 if ((fd = fopen (fName, "w")) == NULL) {
343 fprintf (stderr, "%s: Unable to open GPIO direction interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
344 exit (1) ;
345 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100346
joshua-yang4b08e7f2019-02-21 12:05:24 +0900347 if ((strcasecmp (mode, "in") == 0) || (strcasecmp (mode, "input") == 0))
348 fprintf (fd, "in\n") ;
349 else if ((strcasecmp (mode, "out") == 0) || (strcasecmp (mode, "output") == 0))
350 fprintf (fd, "out\n") ;
351 else if ((strcasecmp (mode, "high") == 0) || (strcasecmp (mode, "up") == 0))
352 fprintf (fd, "high\n") ;
353 else if ((strcasecmp (mode, "low") == 0) || (strcasecmp (mode, "down") == 0))
354 fprintf (fd, "low\n") ;
355 else {
356 fprintf (stderr, "%s: Invalid mode: %s. Should be in, out, high or low\n", argv [1], mode) ;
357 exit (1) ;
358 }
359 fclose (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100360
joshua-yang4b08e7f2019-02-21 12:05:24 +0900361 // Change ownership so the current user can actually use it
362 sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
363 changeOwner (argv [0], fName) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100364
joshua-yang4b08e7f2019-02-21 12:05:24 +0900365 sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
366 changeOwner (argv [0], fName) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100367}
368
369
370/*
Gordon Hendersonda384432013-05-13 19:43:26 +0100371 * doWfi:
372 * gpio wfi pin mode
373 * Wait for Interrupt on a given pin.
374 * Slight cheat here - it's easier to actually use ISR now (which calls
375 * gpio to set the pin modes!) then we simply sleep, and expect the thread
376 * to exit the program. Crude but effective.
377 *********************************************************************************
378 */
joshua-yang4b08e7f2019-02-21 12:05:24 +0900379static void wfi (void) { exit (0) ; }
Gordon Hendersonda384432013-05-13 19:43:26 +0100380
381void doWfi (int argc, char *argv [])
382{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900383 int pin, mode ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100384
joshua-yang4b08e7f2019-02-21 12:05:24 +0900385 if (argc != 4) {
386 fprintf (stderr, "Usage: %s wfi pin mode\n", argv [0]) ;
387 exit (1) ;
388 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100389
joshua-yang4b08e7f2019-02-21 12:05:24 +0900390 pin = atoi (argv [2]) ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100391
joshua-yang4b08e7f2019-02-21 12:05:24 +0900392 if (strcasecmp (argv [3], "rising") == 0) mode = INT_EDGE_RISING ;
393 else if (strcasecmp (argv [3], "falling") == 0) mode = INT_EDGE_FALLING ;
394 else if (strcasecmp (argv [3], "both") == 0) mode = INT_EDGE_BOTH ;
395 else {
396 fprintf (stderr, "%s: wfi: Invalid mode: %s. Should be rising, falling or both\n", argv [1], argv [3]) ;
397 exit (1) ;
398 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100399
joshua-yang4b08e7f2019-02-21 12:05:24 +0900400 if (wiringPiISR (pin, mode, &wfi) < 0) {
401 fprintf (stderr, "%s: wfi: Unable to setup ISR: %s\n", argv [1], strerror (errno)) ;
402 exit (1) ;
403 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100404
joshua-yang4b08e7f2019-02-21 12:05:24 +0900405 for (;;)
406 delay (9999) ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100407}
408
409
Gordon Hendersonda384432013-05-13 19:43:26 +0100410/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100411 * doEdge:
412 * gpio edge pin mode
413 * Easy access to changing the edge trigger on a GPIO pin
414 * This uses the /sys/class/gpio device interface.
415 *********************************************************************************
416 */
417
418void doEdge (int argc, char *argv [])
419{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900420 FILE *fd ;
421 int pin ;
422 char *mode ;
423 char fName [128] ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100424
joshua-yang4b08e7f2019-02-21 12:05:24 +0900425 // Reset gpio sysfs
426 doUnexport(3, argv);
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100427
joshua-yang4b08e7f2019-02-21 12:05:24 +0900428 if (argc != 4) {
429 fprintf (stderr, "Usage: %s edge pin mode\n", argv [0]) ;
430 exit (1) ;
431 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100432
joshua-yang4b08e7f2019-02-21 12:05:24 +0900433 pin = atoi (argv [2]) ;
434 mode = argv [3] ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100435
joshua-yang4b08e7f2019-02-21 12:05:24 +0900436 // Export the pin and set direction to input
437 if ((fd = fopen ("/sys/class/gpio/export", "w")) == NULL) {
438 fprintf (stderr, "%s: Unable to open GPIO export interface: %s\n", argv [0], strerror (errno)) ;
439 exit (1) ;
440 }
441 fprintf (fd, "%d\n", pin) ;
442 fclose (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100443
joshua-yang4b08e7f2019-02-21 12:05:24 +0900444 sprintf (fName, "/sys/class/gpio/gpio%d/direction", pin) ;
445 if ((fd = fopen (fName, "w")) == NULL) {
446 fprintf (stderr, "%s: Unable to open GPIO direction interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
447 exit (1) ;
448 }
449 fprintf (fd, "in\n") ;
450 fclose (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100451
joshua-yang4b08e7f2019-02-21 12:05:24 +0900452 sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
453 if ((fd = fopen (fName, "w")) == NULL) {
454 fprintf (stderr, "%s: Unable to open GPIO edge interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
455 exit (1) ;
456 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100457
joshua-yang4b08e7f2019-02-21 12:05:24 +0900458 if (strcasecmp (mode, "none") == 0) fprintf (fd, "none\n") ;
459 else if (strcasecmp (mode, "rising") == 0) fprintf (fd, "rising\n") ;
460 else if (strcasecmp (mode, "falling") == 0) fprintf (fd, "falling\n") ;
461 else if (strcasecmp (mode, "both") == 0) fprintf (fd, "both\n") ;
462 else {
463 fprintf (stderr, "%s: Invalid mode: %s. Should be none, rising, falling or both\n", argv [1], mode) ;
464 exit (1) ;
465 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100466
joshua-yang4b08e7f2019-02-21 12:05:24 +0900467 // Change ownership of the value and edge files, so the current user can actually use it!
468 sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
469 changeOwner (argv [0], fName) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100470
joshua-yang4b08e7f2019-02-21 12:05:24 +0900471 sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
472 changeOwner (argv [0], fName) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100473
joshua-yang4b08e7f2019-02-21 12:05:24 +0900474 fclose (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100475}
476
477
478/*
479 * doUnexport:
480 * gpio unexport pin
481 * This uses the /sys/class/gpio device interface.
482 *********************************************************************************
483 */
484
485void doUnexport (int argc, char *argv [])
486{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900487 FILE *fd ;
488 int pin ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100489
joshua-yang4b08e7f2019-02-21 12:05:24 +0900490 if (argc != 3) {
491 fprintf (stderr, "Usage: %s unexport pin\n", argv [0]) ;
492 exit (1) ;
493 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100494
joshua-yang4b08e7f2019-02-21 12:05:24 +0900495 pin = atoi (argv [2]) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100496
joshua-yang4b08e7f2019-02-21 12:05:24 +0900497 if ((fd = fopen ("/sys/class/gpio/unexport", "w")) == NULL) {
498 fprintf (stderr, "%s: Unable to open GPIO export interface\n", argv [0]) ;
499 exit (1) ;
500 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100501
joshua-yang4b08e7f2019-02-21 12:05:24 +0900502 fprintf (fd, "%d\n", pin) ;
503 fclose (fd) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100504}
505
506
507/*
508 * doUnexportAll:
509 * gpio unexportall
510 * Un-Export all the GPIO pins.
511 * This uses the /sys/class/gpio device interface.
512 *********************************************************************************
513 */
514
Gordon Hendersonda384432013-05-13 19:43:26 +0100515void doUnexportall (char *progName)
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100516{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900517 FILE *fd ;
518 int pin ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100519
joshua-yang4b08e7f2019-02-21 12:05:24 +0900520 for (pin = 0 ; pin < 256 ; ++pin) {
521 if ((fd = fopen ("/sys/class/gpio/unexport", "w")) == NULL) {
522 fprintf (stderr, "%s: Unable to open GPIO export interface\n", progName) ;
523 exit (1) ;
524 }
525 fprintf (fd, "%d\n", pin) ;
526 fclose (fd) ;
527 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100528}
529
Gordon Hendersonda384432013-05-13 19:43:26 +0100530/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100531 * doMode:
532 * gpio mode pin mode ...
533 *********************************************************************************
534 */
535
536void doMode (int argc, char *argv [])
537{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900538 int pin ;
539 char *mode ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100540
joshua-yang4b08e7f2019-02-21 12:05:24 +0900541 if (argc != 4) {
542 fprintf (stderr, "Usage: %s mode pin mode\n", argv [0]) ;
543 exit (1) ;
544 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100545
joshua-yang4b08e7f2019-02-21 12:05:24 +0900546 pin = atoi (argv [2]) ;
547 mode = argv [3] ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100548
joshua-yang4b08e7f2019-02-21 12:05:24 +0900549 if (strcasecmp (mode, "in") == 0) pinMode (pin, INPUT) ;
550 else if (strcasecmp (mode, "input") == 0) pinMode (pin, INPUT) ;
551 else if (strcasecmp (mode, "out") == 0) pinMode (pin, OUTPUT) ;
552 else if (strcasecmp (mode, "output") == 0) pinMode (pin, OUTPUT) ;
553 else if (strcasecmp (mode, "pwm") == 0) pinMode (pin, PWM_OUTPUT) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900554 else if (strcasecmp (mode, "up") == 0) pullUpDnControl (pin, PUD_UP) ;
555 else if (strcasecmp (mode, "down") == 0) pullUpDnControl (pin, PUD_DOWN) ;
556 else if (strcasecmp (mode, "tri") == 0) pullUpDnControl (pin, PUD_OFF) ;
557 else if (strcasecmp (mode, "off") == 0) pullUpDnControl (pin, PUD_OFF) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900558 else {
559 fprintf (stderr, "%s: Invalid mode: %s. Should be in/out/pwm/clock/up/down/tri\n", argv [1], mode) ;
560 exit (1) ;
561 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100562}
563
564
565/*
566 * doPadDrive:
joshua-yang4b08e7f2019-02-21 12:05:24 +0900567 * gpio drive pin value for ODROIDs since it depends on the SoC
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100568 *********************************************************************************
569 */
570
Gordon Henderson1bb49892012-08-19 15:33:26 +0100571static void doPadDrive (int argc, char *argv [])
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100572{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900573 int pin, val;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100574
joshua-yang4b08e7f2019-02-21 12:05:24 +0900575 if (argc != 4) {
576 fprintf (stderr, "Usage: %s drive pin value\n", argv [0]) ;
577 exit (1) ;
578 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100579
joshua-yang4b08e7f2019-02-21 12:05:24 +0900580 pin = atoi (argv [2]) ;
581 val = atoi (argv [3]) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100582
joshua-yang4b08e7f2019-02-21 12:05:24 +0900583 setPadDrive (pin, val) ;
Gordon Hendersondf453882014-07-17 22:23:57 +0100584}
585
Gordon Henderson99095e32012-08-27 20:56:14 +0100586/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100587 * doWrite:
588 * gpio write pin value
589 *********************************************************************************
590 */
591
Gordon Henderson1bb49892012-08-19 15:33:26 +0100592static void doWrite (int argc, char *argv [])
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100593{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900594 int pin, val ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100595
joshua-yang4b08e7f2019-02-21 12:05:24 +0900596 if (argc != 4) {
597 fprintf (stderr, "Usage: %s write pin value\n", argv [0]) ;
598 exit (1) ;
599 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100600
joshua-yang4b08e7f2019-02-21 12:05:24 +0900601 pin = atoi (argv [2]) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100602
joshua-yang4b08e7f2019-02-21 12:05:24 +0900603 if ((strcasecmp (argv [3], "up") == 0) || (strcasecmp (argv [3], "on") == 0))
604 val = 1 ;
605 else if ((strcasecmp (argv [3], "down") == 0) || (strcasecmp (argv [3], "off") == 0))
606 val = 0 ;
607 else
608 val = atoi (argv [3]) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100609
joshua-yang4b08e7f2019-02-21 12:05:24 +0900610 if (val == 0)
611 digitalWrite (pin, LOW) ;
612 else
613 digitalWrite (pin, HIGH) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100614}
615
Gordon Henderson25e4ec52012-12-06 21:49:41 +0000616/*
617 * doWriteByte:
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000618 * gpio wb value
Gordon Henderson25e4ec52012-12-06 21:49:41 +0000619 *********************************************************************************
620 */
621
622static void doWriteByte (int argc, char *argv [])
623{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900624 int val ;
Gordon Henderson25e4ec52012-12-06 21:49:41 +0000625
joshua-yang4b08e7f2019-02-21 12:05:24 +0900626 if (argc != 3) {
627 fprintf (stderr, "Usage: %s wb value\n", argv [0]) ;
628 exit (1) ;
629 }
630 val = (int)strtol (argv [2], NULL, 0) ;
Gordon Henderson25e4ec52012-12-06 21:49:41 +0000631
joshua-yang4b08e7f2019-02-21 12:05:24 +0900632 digitalWriteByte (val) ;
Gordon Henderson25e4ec52012-12-06 21:49:41 +0000633}
634
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100635
636/*
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000637 * doReadByte:
638 * gpio rbx|rbd value
639 *********************************************************************************
640 */
641
642static void doReadByte (int argc, char *argv [], int printHex)
643{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900644 int val ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000645
joshua-yang4b08e7f2019-02-21 12:05:24 +0900646 if (argc != 2) {
647 fprintf (stderr, "Usage: %s rbx|rbd\n", argv [0]) ;
648 exit (1) ;
649 }
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000650
joshua-yang4b08e7f2019-02-21 12:05:24 +0900651 val = digitalReadByte () ;
652 if (printHex)
653 printf ("%02X\n", val) ;
654 else
655 printf ("%d\n", val) ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000656}
657
658
659/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100660 * doRead:
661 * Read a pin and return the value
662 *********************************************************************************
663 */
664
Joshua Yang6e7a6e62019-07-09 15:57:26 +0900665void doRead (int argc, char *argv [])
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100666{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900667 int pin, val ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100668
joshua-yang4b08e7f2019-02-21 12:05:24 +0900669 if (argc != 3) {
670 fprintf (stderr, "Usage: %s read pin\n", argv [0]) ;
671 exit (1) ;
672 }
673 pin = atoi (argv [2]) ;
674 val = digitalRead (pin) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100675
joshua-yang4b08e7f2019-02-21 12:05:24 +0900676 printf ("%s\n", val == 0 ? "0" : "1") ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100677}
678
679
680/*
Gordon Hendersonda384432013-05-13 19:43:26 +0100681 * doAread:
682 * Read an analog pin and return the value
683 *********************************************************************************
684 */
685
Joshua Yang6e7a6e62019-07-09 15:57:26 +0900686void doAread (int argc, char *argv [])
Gordon Hendersonda384432013-05-13 19:43:26 +0100687{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900688 if (argc != 3) {
689 fprintf (stderr, "Usage: %s aread pin\n", argv [0]) ;
690 exit (1) ;
691 }
692 printf ("%d\n", analogRead (atoi (argv [2]))) ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100693}
694
695
696/*
697 * doToggle:
698 * Toggle an IO pin
699 *********************************************************************************
700 */
701
702void doToggle (int argc, char *argv [])
703{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900704 int pin ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100705
joshua-yang4b08e7f2019-02-21 12:05:24 +0900706 if (argc != 3) {
707 fprintf (stderr, "Usage: %s toggle pin\n", argv [0]) ;
708 exit (1) ;
709 }
710 pin = atoi (argv [2]) ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100711
joshua-yang4b08e7f2019-02-21 12:05:24 +0900712 digitalWrite (pin, !digitalRead (pin)) ;
Gordon Hendersonda384432013-05-13 19:43:26 +0100713}
714
Gordon Hendersondca8a192014-07-14 08:39:38 +0100715
716/*
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000717 * doBlink:
718 * Blink an IO pin
719 *********************************************************************************
720 */
721
722void doBlink (int argc, char *argv [])
723{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900724 int pin ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000725
joshua-yang4b08e7f2019-02-21 12:05:24 +0900726 if (argc != 3) {
727 fprintf (stderr, "Usage: %s blink pin\n", argv [0]) ;
728 exit (1) ;
729 }
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000730
joshua-yang4b08e7f2019-02-21 12:05:24 +0900731 pin = atoi (argv [2]) ;
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000732
joshua-yang4b08e7f2019-02-21 12:05:24 +0900733 pinMode (pin, OUTPUT) ;
734 for (;;) {
735 digitalWrite (pin, !digitalRead (pin)) ;
736 delay (500) ;
737 }
Gordon Hendersonb1dfc182016-12-12 14:19:55 +0000738}
739
Gordon Henderson56c77b52013-02-01 20:19:22 +0000740/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100741 * doPwm:
742 * Output a PWM value on a pin
743 *********************************************************************************
744 */
745
746void doPwm (int argc, char *argv [])
747{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900748 int pin, val ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100749
joshua-yang4b08e7f2019-02-21 12:05:24 +0900750 if (argc != 4) {
751 fprintf (stderr, "Usage: %s pwm <pin> <value>\n", argv [0]) ;
752 exit (1) ;
753 }
754 pin = atoi (argv [2]) ;
755 val = atoi (argv [3]) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100756
joshua-yang4b08e7f2019-02-21 12:05:24 +0900757 pwmWrite (pin, val) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100758}
759
760
761/*
Gordon Henderson8cb49392012-09-16 10:15:32 +0100762 * doPwmMode: doPwmRange: doPwmClock:
763 * Change the PWM mode, range and clock divider values
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100764 *********************************************************************************
765 */
766
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900767static void doPwmMode (int mode)
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100768{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900769 pwmSetMode (mode) ;
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100770}
771
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900772static void doPwmRange (int argc, char *argv [])
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100773{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900774 unsigned int range ;
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100775
joshua-yang4b08e7f2019-02-21 12:05:24 +0900776 if (argc != 3) {
777 fprintf (stderr, "Usage: %s pwmr <range>\n", argv [0]) ;
778 exit (1) ;
779 }
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100780
joshua-yang4b08e7f2019-02-21 12:05:24 +0900781 range = (unsigned int)strtoul (argv [2], NULL, 10) ;
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100782
joshua-yang4b08e7f2019-02-21 12:05:24 +0900783 if (range == 0) {
784 fprintf (stderr, "%s: range must be > 0\n", argv [0]) ;
785 exit (1) ;
786 }
787 pwmSetRange (range) ;
Gordon Hendersonf99ffed2012-08-19 15:12:45 +0100788}
789
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900790static void doPwmClock (int argc, char *argv [])
Gordon Henderson8cb49392012-09-16 10:15:32 +0100791{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900792 unsigned int clock ;
Gordon Henderson8cb49392012-09-16 10:15:32 +0100793
joshua-yang4b08e7f2019-02-21 12:05:24 +0900794 if (argc != 3) {
795 fprintf (stderr, "Usage: %s pwmc <clock>\n", argv [0]) ;
796 exit (1) ;
797 }
Gordon Henderson8cb49392012-09-16 10:15:32 +0100798
joshua-yang4b08e7f2019-02-21 12:05:24 +0900799 clock = (unsigned int)strtoul (argv [2], NULL, 10) ;
Gordon Henderson8cb49392012-09-16 10:15:32 +0100800
joshua-yang4b08e7f2019-02-21 12:05:24 +0900801 if ((clock < 1) || (clock > 4095)) {
802 fprintf (stderr, "%s: clock must be between 0 and 4096\n", argv [0]) ;
803 exit (1) ;
804 }
805 pwmSetClock (clock) ;
Gordon Henderson8cb49392012-09-16 10:15:32 +0100806}
807
joshua-yang4b08e7f2019-02-21 12:05:24 +0900808/*
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000809 * doVersion:
Gordon Hendersonb0a60c32016-02-29 06:57:38 +0000810 * Handle the ever more complicated version command and print out
811 * some usefull information.
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000812 *********************************************************************************
813 */
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000814static void doVersion (char *argv [])
815{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900816 int model, rev, mem, maker, warranty ;
817 struct stat statBuf ;
818 char name [80] ;
819 FILE *fd ;
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000820
Joshua Yang41a423e2019-07-16 18:08:16 +0900821 int vMaj;
822 char *vMin[32];
Gordon Hendersone687f3f2017-01-24 12:13:39 +0000823
Joshua Yang41a423e2019-07-16 18:08:16 +0900824 wiringPiVersion (&vMaj, vMin) ;
825 printf ("gpio version: %d.%s\n", vMaj, *vMin) ;
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900826 printf ("Copyright (c) 2012-2017 Gordon Henderson, 2017-2020 Hardkernel Co., Ltd.\n") ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900827 printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ;
828 printf ("For details type: %s -warranty\n", argv [0]) ;
829 printf ("\n") ;
830 piBoardId (&model, &rev, &mem, &maker, &warranty) ;
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000831
joshua-yang4b08e7f2019-02-21 12:05:24 +0900832 printf ("ODROID Board Details:\n") ;
833 printf (" Type: %s, Revision: %s, Memory: %dMB\n" \
Joshua Yang6e7a6e62019-07-09 15:57:26 +0900834 " Maker: %s, Chip-Vendor: %s\n",
joshua-yang4b08e7f2019-02-21 12:05:24 +0900835 piModelNames [model],
836 piRevisionNames [rev],
837 piMemorySize [mem],
838 "Hardkernel",
839 piMakerNames [maker]);
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000840
joshua-yang4b08e7f2019-02-21 12:05:24 +0900841 // Check for device tree
842 if (stat ("/proc/device-tree", &statBuf) == 0) // We're on a devtree system ...
843 printf (" * Device tree is enabled.\n") ;
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000844
joshua-yang4b08e7f2019-02-21 12:05:24 +0900845 // Output Kernel idea of board type
846 if (stat ("/proc/device-tree/model", &statBuf) == 0) {
847 if ((fd = fopen ("/proc/device-tree/model", "r")) != NULL) {
Joshua Yang6e7a6e62019-07-09 15:57:26 +0900848 if (fgets (name, 80, fd) == NULL)
849 fprintf(stderr, "Unable to read from the file descriptor: %s \n", strerror(errno));
joshua-yang4b08e7f2019-02-21 12:05:24 +0900850 fclose (fd) ;
851 printf (" *--> %s\n", name) ;
852 }
853 }
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000854
joshua-yang4b08e7f2019-02-21 12:05:24 +0900855 // User level GPIO is GO
856 if (stat ("/dev/gpiomem", &statBuf) == 0)
857 printf (" * Supports user-level GPIO access.\n") ;
858 else
859 printf (" * Root or sudo required for GPIO access.\n") ;
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000860}
861
862
863/*
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100864 * main:
865 * Start here
866 *********************************************************************************
867 */
868
869int main (int argc, char *argv [])
870{
joshua-yang4b08e7f2019-02-21 12:05:24 +0900871 int i ;
Yang Deokgyu020ff312019-09-11 11:43:05 +0900872 struct stat statBuf ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100873
joshua-yang4b08e7f2019-02-21 12:05:24 +0900874 if (getenv ("WIRINGPI_DEBUG") != NULL) {
875 printf ("gpio: wiringPi debug mode enabled\n") ;
876 wiringPiDebug = TRUE ;
877 }
Gordon Henderson13bbba72013-01-14 11:31:56 +0000878
joshua-yang4b08e7f2019-02-21 12:05:24 +0900879 if (argc == 1) {
880 fprintf (stderr, "%s\n", usage) ;
881 return 1 ;
882 }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100883
joshua-yang4b08e7f2019-02-21 12:05:24 +0900884 // Help
885 if (strcasecmp (argv [1], "-h") == 0) {
886 printf ("%s: %s\n", argv [0], usage) ;
887 return 0 ;
888 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100889
joshua-yang4b08e7f2019-02-21 12:05:24 +0900890 // Version & Warranty
891 // Wish I could remember why I have both -R and -V ...
892 if ((strcmp (argv [1], "-R") == 0) || (strcmp (argv [1], "-V") == 0)) {
893 printf ("%d\n", piGpioLayout ()) ;
894 return 0 ;
895 }
Gordon Henderson178ea082012-08-19 15:17:03 +0100896
joshua-yang4b08e7f2019-02-21 12:05:24 +0900897 // Version and information
898 if (strcmp (argv [1], "-v") == 0) {
899 doVersion (argv) ;
900 return 0 ;
901 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100902
joshua-yang4b08e7f2019-02-21 12:05:24 +0900903 if (strcasecmp (argv [1], "-warranty") == 0) {
904 printf ("gpio version: %s\n", VERSION) ;
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900905 printf ("Copyright (c) 2012-2017 Gordon Henderson, 2017-2020 Hardkernel Co., Ltd.\n") ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900906 printf ("\n") ;
907 printf (" This program is free software; you can redistribute it and/or modify\n") ;
908 printf (" it under the terms of the GNU Leser General Public License as published\n") ;
909 printf (" by the Free Software Foundation, either version 3 of the License, or\n") ;
910 printf (" (at your option) any later version.\n") ;
911 printf ("\n") ;
912 printf (" This program is distributed in the hope that it will be useful,\n") ;
913 printf (" but WITHOUT ANY WARRANTY; without even the implied warranty of\n") ;
914 printf (" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n") ;
915 printf (" GNU Lesser General Public License for more details.\n") ;
916 printf ("\n") ;
917 printf (" You should have received a copy of the GNU Lesser General Public License\n") ;
918 printf (" along with this program. If not, see <http://www.gnu.org/licenses/>.\n") ;
919 printf ("\n") ;
920 return 0 ;
921 }
Gordon Hendersonda384432013-05-13 19:43:26 +0100922
Yang Deokgyu020ff312019-09-11 11:43:05 +0900923 if (geteuid () != 0 && stat("/dev/gpiomem", &statBuf) != 0) {
joshua-yang4b08e7f2019-02-21 12:05:24 +0900924 fprintf (stderr, "%s: Must be root to run. Program should be suid root. This is an error.\n", argv [0]) ;
925 return 1 ;
926 }
Gordon Hendersonbb6f0842015-11-29 21:08:04 +0000927
joshua-yang4b08e7f2019-02-21 12:05:24 +0900928 // Initial test for /sys/class/gpio operations:
929 if (strcasecmp (argv [1], "exports" ) == 0) { doExports (argc, argv) ; return 0 ; }
930 else if (strcasecmp (argv [1], "export" ) == 0) { doExport (argc, argv) ; return 0 ; }
931 else if (strcasecmp (argv [1], "edge" ) == 0) { doEdge (argc, argv) ; return 0 ; }
932 else if (strcasecmp (argv [1], "unexport" ) == 0) { doUnexport (argc, argv) ; return 0 ; }
933 else if (strcasecmp (argv [1], "unexportall") == 0) { doUnexportall (argv [0]) ; return 0 ; }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100934
joshua-yang4b08e7f2019-02-21 12:05:24 +0900935 // Check for load command:
936 if (strcasecmp (argv [1], "load" ) == 0) { doLoad (argc, argv) ; return 0 ; }
937 if (strcasecmp (argv [1], "unload" ) == 0) { doUnLoad (argc, argv) ; return 0 ; }
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100938
joshua-yang4b08e7f2019-02-21 12:05:24 +0900939 // Check for allreadall command, force Gpio mode
940 if (strcasecmp (argv [1], "allreadall") == 0) {
941 wiringPiSetupGpio () ;
942 doAllReadall () ;
943 return 0 ;
944 }
Gordon Henderson178ea082012-08-19 15:17:03 +0100945
joshua-yang4b08e7f2019-02-21 12:05:24 +0900946 if (strcasecmp (argv [1], "-g") == 0) { // Check for -g argument
947 wiringPiSetupGpio () ;
Gordon Henderson178ea082012-08-19 15:17:03 +0100948
joshua-yang4b08e7f2019-02-21 12:05:24 +0900949 for (i = 2 ; i < argc ; ++i)
950 argv [i - 1] = argv [i] ;
951 --argc ;
952 wpMode = MODE_GPIO ;
953 } else if (strcasecmp (argv [1], "-1") == 0) { // Check for -1 argument
954 wiringPiSetupPhys () ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100955
joshua-yang4b08e7f2019-02-21 12:05:24 +0900956 for (i = 2 ; i < argc ; ++i)
957 argv [i - 1] = argv [i] ;
958 --argc ;
959 wpMode = MODE_PHYS ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900960 } else if (strcasecmp (argv [1], "-z") == 0) { // Check for -z argument so we don't actually initialise wiringPi
961 for (i = 2 ; i < argc ; ++i)
962 argv [i - 1] = argv [i] ;
963 --argc ;
964 wpMode = MODE_UNINITIALISED ;
965 } else { // Default to wiringPi mode
966 wiringPiSetup () ;
967 wpMode = MODE_PINS ;
968 }
Gordon Hendersonb0a60c32016-02-29 06:57:38 +0000969
joshua-yang4b08e7f2019-02-21 12:05:24 +0900970 if (argc <= 1) {
971 fprintf (stderr, "%s: no command given\n", argv [0]) ;
972 exit (EXIT_FAILURE) ;
973 }
Gordon Hendersonb0a60c32016-02-29 06:57:38 +0000974
joshua-yang4b08e7f2019-02-21 12:05:24 +0900975 // Core wiringPi functions
976 /**/ if (strcasecmp (argv [1], "mode" ) == 0) doMode (argc, argv) ;
977 else if (strcasecmp (argv [1], "read" ) == 0) doRead (argc, argv) ;
978 else if (strcasecmp (argv [1], "write" ) == 0) doWrite (argc, argv) ;
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900979 else if (strcasecmp (argv [1], "pwm" ) == 0) doPwm (argc, argv) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900980 else if (strcasecmp (argv [1], "aread" ) == 0) doAread (argc, argv) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100981
joshua-yang4b08e7f2019-02-21 12:05:24 +0900982 // GPIO Nicies
983 else if (strcasecmp (argv [1], "toggle" ) == 0) doToggle (argc, argv) ;
984 else if (strcasecmp (argv [1], "blink" ) == 0) doBlink (argc, argv) ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +0100985
joshua-yang4b08e7f2019-02-21 12:05:24 +0900986 // Pi Specifics
Deokgyu Yang89cf23c2020-03-19 17:21:21 +0900987 else if (strcasecmp (argv [1], "pwm-bal" ) == 0) doPwmMode (PWM_MODE_BAL) ;
988 else if (strcasecmp (argv [1], "pwm-ms" ) == 0) doPwmMode (PWM_MODE_MS) ;
989 else if (strcasecmp (argv [1], "pwmr" ) == 0) doPwmRange (argc, argv) ;
990 else if (strcasecmp (argv [1], "pwmc" ) == 0) doPwmClock (argc, argv) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900991 else if (strcasecmp (argv [1], "drive" ) == 0) doPadDrive (argc, argv) ;
Yang Deokgyu5106f2a2019-09-20 12:27:57 +0900992 else if (strcasecmp (argv [1], "readall" ) == 0) doReadall (argc, argv) ;
993 else if (strcasecmp (argv [1], "nreadall" ) == 0) doReadall (argc, argv) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900994 else if (strcasecmp (argv [1], "i2cdetect") == 0) doI2Cdetect (argc, argv) ;
995 else if (strcasecmp (argv [1], "i2cd" ) == 0) doI2Cdetect (argc, argv) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900996 else if (strcasecmp (argv [1], "wb" ) == 0) doWriteByte (argc, argv) ;
997 else if (strcasecmp (argv [1], "rbx" ) == 0) doReadByte (argc, argv, TRUE) ;
998 else if (strcasecmp (argv [1], "rbd" ) == 0) doReadByte (argc, argv, FALSE) ;
joshua-yang4b08e7f2019-02-21 12:05:24 +0900999 else if (strcasecmp (argv [1], "wfi" ) == 0) doWfi (argc, argv) ;
1000 else {
1001 fprintf (stderr, "%s: Unknown command: %s.\n", argv [0], argv [1]) ;
1002 exit (EXIT_FAILURE) ;
1003 }
1004 return 0 ;
Gordon Hendersonbf0ad862012-08-16 15:04:43 +01001005}