Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 

778 Zeilen
18 KiB

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