wpiExtensions.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. /*
  2. * extensions.c:
  3. * Originally part of the GPIO program to test, peek, poke and otherwise
  4. * noodle with the GPIO hardware on the Raspberry Pi.
  5. * Now used as a general purpose library to allow systems to dynamically
  6. * add in new devices into wiringPi at program run-time.
  7. * Copyright (c) 2012-2015 Gordon Henderson
  8. ***********************************************************************
  9. * This file is part of wiringPi:
  10. * https://projects.drogon.net/raspberry-pi/wiringpi/
  11. *
  12. * wiringPi is free software: you can redistribute it and/or modify
  13. * it under the terms of the GNU Lesser General Public License as published by
  14. * the Free Software Foundation, either version 3 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * wiringPi is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU Lesser General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Lesser General Public License
  23. * along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
  24. ***********************************************************************
  25. */
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <stdint.h>
  29. #include <stdarg.h>
  30. #include <ctype.h>
  31. #include <string.h>
  32. #include <unistd.h>
  33. #include <errno.h>
  34. #include <sys/types.h>
  35. #include <fcntl.h>
  36. #include <wiringPi.h>
  37. #include "mcp23008.h"
  38. #include "mcp23016.h"
  39. #include "mcp23017.h"
  40. #include "mcp23s08.h"
  41. #include "mcp23s17.h"
  42. #include "sr595.h"
  43. #include "pcf8591.h"
  44. #include "pcf8574.h"
  45. #include "max31855.h"
  46. #include "max5322.h"
  47. #include "mcp3002.h"
  48. #include "mcp3004.h"
  49. #include "mcp4802.h"
  50. #include "mcp3422.h"
  51. #include "sn3218.h"
  52. #include "drcSerial.h"
  53. #include "wpiExtensions.h"
  54. extern int wiringPiDebug ;
  55. static int verbose ;
  56. static char errorMessage [1024] ;
  57. #ifndef TRUE
  58. # define TRUE (1==1)
  59. # define FALSE (1==2)
  60. #endif
  61. // Local structure to hold details
  62. struct extensionFunctionStruct
  63. {
  64. const char *name ;
  65. int (*function)(char *progName, int pinBase, char *params) ;
  66. } ;
  67. /*
  68. * verbError:
  69. * Convenient error handling
  70. *********************************************************************************
  71. */
  72. static void verbError (const char *message, ...)
  73. {
  74. va_list argp ;
  75. va_start (argp, message) ;
  76. vsnprintf (errorMessage, 1023, message, argp) ;
  77. va_end (argp) ;
  78. if (verbose)
  79. fprintf (stderr, "%s\n", errorMessage) ;
  80. }
  81. /*
  82. * extractInt:
  83. * Check & return an integer at the given location (prefixed by a :)
  84. *********************************************************************************
  85. */
  86. static char *extractInt (char *progName, char *p, int *num)
  87. {
  88. if (*p != ':')
  89. {
  90. verbError ("%s: colon expected", progName) ;
  91. return NULL ;
  92. }
  93. ++p ;
  94. if (!isdigit (*p))
  95. {
  96. verbError ("%s: digit expected", progName) ;
  97. return NULL ;
  98. }
  99. *num = strtol (p, NULL, 0) ;
  100. while (isdigit (*p))
  101. ++p ;
  102. return p ;
  103. }
  104. /*
  105. * extractStr:
  106. * Check & return a string at the given location (prefixed by a :)
  107. *********************************************************************************
  108. */
  109. static char *extractStr (char *progName, char *p, char **str)
  110. {
  111. char *q, *r ;
  112. if (*p != ':')
  113. {
  114. verbError ("%s: colon expected", progName) ;
  115. return NULL ;
  116. }
  117. ++p ;
  118. if (!isprint (*p))
  119. {
  120. verbError ("%s: character expected", progName) ;
  121. return NULL ;
  122. }
  123. q = p ;
  124. while ((*q != 0) && (*q != ':'))
  125. ++q ;
  126. *str = r = calloc (q - p + 2, 1) ; // Zeros it
  127. while (p != q)
  128. *r++ = *p++ ;
  129. return p ;
  130. }
  131. /*
  132. * doExtensionMcp23008:
  133. * MCP23008 - 8-bit I2C GPIO expansion chip
  134. * mcp23002:base:i2cAddr
  135. *********************************************************************************
  136. */
  137. static int doExtensionMcp23008 (char *progName, int pinBase, char *params)
  138. {
  139. int i2c ;
  140. if ((params = extractInt (progName, params, &i2c)) == NULL)
  141. return FALSE ;
  142. if ((i2c < 0x01) || (i2c > 0x77))
  143. {
  144. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  145. return FALSE ;
  146. }
  147. mcp23008Setup (pinBase, i2c) ;
  148. return TRUE ;
  149. }
  150. /*
  151. * doExtensionMcp23016:
  152. * MCP230016- 16-bit I2C GPIO expansion chip
  153. * mcp23016:base:i2cAddr
  154. *********************************************************************************
  155. */
  156. static int doExtensionMcp23016 (char *progName, int pinBase, char *params)
  157. {
  158. int i2c ;
  159. if ((params = extractInt (progName, params, &i2c)) == NULL)
  160. return FALSE ;
  161. if ((i2c < 0x03) || (i2c > 0x77))
  162. {
  163. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  164. return FALSE ;
  165. }
  166. mcp23016Setup (pinBase, i2c) ;
  167. return TRUE ;
  168. }
  169. /*
  170. * doExtensionMcp23017:
  171. * MCP230017- 16-bit I2C GPIO expansion chip
  172. * mcp23017:base:i2cAddr
  173. *********************************************************************************
  174. */
  175. static int doExtensionMcp23017 (char *progName, int pinBase, char *params)
  176. {
  177. int i2c ;
  178. if ((params = extractInt (progName, params, &i2c)) == NULL)
  179. return FALSE ;
  180. if ((i2c < 0x03) || (i2c > 0x77))
  181. {
  182. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  183. return FALSE ;
  184. }
  185. mcp23017Setup (pinBase, i2c) ;
  186. return TRUE ;
  187. }
  188. /*
  189. * doExtensionMcp23s08:
  190. * MCP23s08 - 8-bit SPI GPIO expansion chip
  191. * mcp23s08:base:spi:port
  192. *********************************************************************************
  193. */
  194. static int doExtensionMcp23s08 (char *progName, int pinBase, char *params)
  195. {
  196. int spi, port ;
  197. if ((params = extractInt (progName, params, &spi)) == NULL)
  198. return FALSE ;
  199. if ((spi < 0) || (spi > 1))
  200. {
  201. verbError ("%s: SPI address (%d) out of range", progName, spi) ;
  202. return FALSE ;
  203. }
  204. if ((params = extractInt (progName, params, &port)) == NULL)
  205. return FALSE ;
  206. if ((port < 0) || (port > 7))
  207. {
  208. verbError ("%s: port address (%d) out of range", progName, port) ;
  209. return FALSE ;
  210. }
  211. mcp23s08Setup (pinBase, spi, port) ;
  212. return TRUE ;
  213. }
  214. /*
  215. * doExtensionMcp23s17:
  216. * MCP23s17 - 16-bit SPI GPIO expansion chip
  217. * mcp23s17:base:spi:port
  218. *********************************************************************************
  219. */
  220. static int doExtensionMcp23s17 (char *progName, int pinBase, char *params)
  221. {
  222. int spi, port ;
  223. if ((params = extractInt (progName, params, &spi)) == NULL)
  224. return FALSE ;
  225. if ((spi < 0) || (spi > 1))
  226. {
  227. verbError ("%s: SPI address (%d) out of range", progName, spi) ;
  228. return FALSE ;
  229. }
  230. if ((params = extractInt (progName, params, &port)) == NULL)
  231. return FALSE ;
  232. if ((port < 0) || (port > 7))
  233. {
  234. verbError ("%s: port address (%d) out of range", progName, port) ;
  235. return FALSE ;
  236. }
  237. mcp23s17Setup (pinBase, spi, port) ;
  238. return TRUE ;
  239. }
  240. /*
  241. * doExtensionSr595:
  242. * Shift Register 74x595
  243. * sr595:base:pins:data:clock:latch
  244. *********************************************************************************
  245. */
  246. static int doExtensionSr595 (char *progName, int pinBase, char *params)
  247. {
  248. int pins, data, clock, latch ;
  249. // Extract pins
  250. if ((params = extractInt (progName, params, &pins)) == NULL)
  251. return FALSE ;
  252. if ((pins < 8) || (pins > 32))
  253. {
  254. verbError ("%s: pin count (%d) out of range - 8-32 expected.", progName, pins) ;
  255. return FALSE ;
  256. }
  257. if ((params = extractInt (progName, params, &data)) == NULL)
  258. return FALSE ;
  259. if ((params = extractInt (progName, params, &clock)) == NULL)
  260. return FALSE ;
  261. if ((params = extractInt (progName, params, &latch)) == NULL)
  262. return FALSE ;
  263. sr595Setup (pinBase, pins, data, clock, latch) ;
  264. return TRUE ;
  265. }
  266. /*
  267. * doExtensionPcf8574:
  268. * Digital IO (Crude!)
  269. * pcf8574:base:i2cAddr
  270. *********************************************************************************
  271. */
  272. static int doExtensionPcf8574 (char *progName, int pinBase, char *params)
  273. {
  274. int i2c ;
  275. if ((params = extractInt (progName, params, &i2c)) == NULL)
  276. return FALSE ;
  277. if ((i2c < 0x03) || (i2c > 0x77))
  278. {
  279. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  280. return FALSE ;
  281. }
  282. pcf8574Setup (pinBase, i2c) ;
  283. return TRUE ;
  284. }
  285. /*
  286. * doExtensionPcf8591:
  287. * Analog IO
  288. * pcf8591:base:i2cAddr
  289. *********************************************************************************
  290. */
  291. static int doExtensionPcf8591 (char *progName, int pinBase, char *params)
  292. {
  293. int i2c ;
  294. if ((params = extractInt (progName, params, &i2c)) == NULL)
  295. return FALSE ;
  296. if ((i2c < 0x03) || (i2c > 0x77))
  297. {
  298. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  299. return FALSE ;
  300. }
  301. pcf8591Setup (pinBase, i2c) ;
  302. return TRUE ;
  303. }
  304. /*
  305. * doExtensionMax31855:
  306. * Analog IO
  307. * max31855:base:spiChan
  308. *********************************************************************************
  309. */
  310. static int doExtensionMax31855 (char *progName, int pinBase, char *params)
  311. {
  312. int spi ;
  313. if ((params = extractInt (progName, params, &spi)) == NULL)
  314. return FALSE ;
  315. if ((spi < 0) || (spi > 1))
  316. {
  317. verbError ("%s: SPI channel (%d) out of range", progName, spi) ;
  318. return FALSE ;
  319. }
  320. max31855Setup (pinBase, spi) ;
  321. return TRUE ;
  322. }
  323. /*
  324. * doExtensionMcp3002:
  325. * Analog IO
  326. * mcp3002:base:spiChan
  327. *********************************************************************************
  328. */
  329. static int doExtensionMcp3002 (char *progName, int pinBase, char *params)
  330. {
  331. int spi ;
  332. if ((params = extractInt (progName, params, &spi)) == NULL)
  333. return FALSE ;
  334. if ((spi < 0) || (spi > 1))
  335. {
  336. verbError ("%s: SPI channel (%d) out of range", progName, spi) ;
  337. return FALSE ;
  338. }
  339. mcp3002Setup (pinBase, spi) ;
  340. return TRUE ;
  341. }
  342. /*
  343. * doExtensionMcp3004:
  344. * Analog IO
  345. * mcp3004:base:spiChan
  346. *********************************************************************************
  347. */
  348. static int doExtensionMcp3004 (char *progName, int pinBase, char *params)
  349. {
  350. int spi ;
  351. if ((params = extractInt (progName, params, &spi)) == NULL)
  352. return FALSE ;
  353. if ((spi < 0) || (spi > 1))
  354. {
  355. verbError ("%s: SPI channel (%d) out of range", progName, spi) ;
  356. return FALSE ;
  357. }
  358. mcp3004Setup (pinBase, spi) ;
  359. return TRUE ;
  360. }
  361. /*
  362. * doExtensionMax5322:
  363. * Analog O
  364. * max5322:base:spiChan
  365. *********************************************************************************
  366. */
  367. static int doExtensionMax5322 (char *progName, int pinBase, char *params)
  368. {
  369. int spi ;
  370. if ((params = extractInt (progName, params, &spi)) == NULL)
  371. return FALSE ;
  372. if ((spi < 0) || (spi > 1))
  373. {
  374. verbError ("%s: SPI channel (%d) out of range", progName, spi) ;
  375. return FALSE ;
  376. }
  377. max5322Setup (pinBase, spi) ;
  378. return TRUE ;
  379. }
  380. /*
  381. * doExtensionMcp4802:
  382. * Analog IO
  383. * mcp4802:base:spiChan
  384. *********************************************************************************
  385. */
  386. static int doExtensionMcp4802 (char *progName, int pinBase, char *params)
  387. {
  388. int spi ;
  389. if ((params = extractInt (progName, params, &spi)) == NULL)
  390. return FALSE ;
  391. if ((spi < 0) || (spi > 1))
  392. {
  393. verbError ("%s: SPI channel (%d) out of range", progName, spi) ;
  394. return FALSE ;
  395. }
  396. mcp4802Setup (pinBase, spi) ;
  397. return TRUE ;
  398. }
  399. /*
  400. * doExtensionSn3218:
  401. * Analog Output (LED Driver)
  402. * sn3218:base
  403. *********************************************************************************
  404. */
  405. static int doExtensionSn3218 (char *progName, int pinBase, char *params)
  406. {
  407. sn3218Setup (pinBase) ;
  408. return TRUE ;
  409. }
  410. /*
  411. * doExtensionMcp3422:
  412. * Analog IO
  413. * mcp3422:base:i2cAddr
  414. *********************************************************************************
  415. */
  416. static int doExtensionMcp3422 (char *progName, int pinBase, char *params)
  417. {
  418. int i2c, sampleRate, gain ;
  419. if ((params = extractInt (progName, params, &i2c)) == NULL)
  420. return FALSE ;
  421. if ((i2c < 0x03) || (i2c > 0x77))
  422. {
  423. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  424. return FALSE ;
  425. }
  426. if ((params = extractInt (progName, params, &sampleRate)) == NULL)
  427. return FALSE ;
  428. if ((sampleRate < 0) || (sampleRate > 3))
  429. {
  430. verbError ("%s: sample rate (%d) out of range", progName, sampleRate) ;
  431. return FALSE ;
  432. }
  433. if ((params = extractInt (progName, params, &gain)) == NULL)
  434. return FALSE ;
  435. if ((gain < 0) || (gain > 3))
  436. {
  437. verbError ("%s: gain (%d) out of range", progName, gain) ;
  438. return FALSE ;
  439. }
  440. mcp3422Setup (pinBase, i2c, sampleRate, gain) ;
  441. return TRUE ;
  442. }
  443. /*
  444. * doExtensionDrcS:
  445. * Interface to a DRC Serial system
  446. * drcs:base:pins:serialPort:baud
  447. *********************************************************************************
  448. */
  449. static int doExtensionDrcS (char *progName, int pinBase, char *params)
  450. {
  451. char *port ;
  452. int pins, baud ;
  453. if ((params = extractInt (progName, params, &pins)) == NULL)
  454. return FALSE ;
  455. if ((pins < 1) || (pins > 100))
  456. {
  457. verbError ("%s: pins (%d) out of range (2-100)", progName, pins) ;
  458. return FALSE ;
  459. }
  460. if ((params = extractStr (progName, params, &port)) == NULL)
  461. return FALSE ;
  462. if (strlen (port) == 0)
  463. {
  464. verbError ("%s: serial port device name required", progName) ;
  465. return FALSE ;
  466. }
  467. if ((params = extractInt (progName, params, &baud)) == NULL)
  468. return FALSE ;
  469. if ((baud < 1) || (baud > 4000000))
  470. {
  471. verbError ("%s: baud rate (%d) out of range", progName, baud) ;
  472. return FALSE ;
  473. }
  474. drcSetupSerial (pinBase, pins, port, baud) ;
  475. return TRUE ;
  476. }
  477. /*
  478. * Function list
  479. *********************************************************************************
  480. */
  481. static struct extensionFunctionStruct extensionFunctions [] =
  482. {
  483. { "mcp23008", &doExtensionMcp23008 },
  484. { "mcp23016", &doExtensionMcp23016 },
  485. { "mcp23017", &doExtensionMcp23017 },
  486. { "mcp23s08", &doExtensionMcp23s08 },
  487. { "mcp23s17", &doExtensionMcp23s17 },
  488. { "sr595", &doExtensionSr595 },
  489. { "pcf8574", &doExtensionPcf8574 },
  490. { "pcf8591", &doExtensionPcf8591 },
  491. { "mcp3002", &doExtensionMcp3002 },
  492. { "mcp3004", &doExtensionMcp3004 },
  493. { "mcp4802", &doExtensionMcp4802 },
  494. { "mcp3422", &doExtensionMcp3422 },
  495. { "max31855", &doExtensionMax31855 },
  496. { "max5322", &doExtensionMax5322 },
  497. { "sn3218", &doExtensionSn3218 },
  498. { "drcs", &doExtensionDrcS },
  499. { NULL, NULL },
  500. } ;
  501. /*
  502. * loadWPiExtension:
  503. * Load in a wiringPi extension
  504. *********************************************************************************
  505. */
  506. int loadWPiExtension (char *progName, char *extensionData, int printErrors)
  507. {
  508. char *p ;
  509. char *extension = extensionData ;
  510. struct extensionFunctionStruct *extensionFn ;
  511. int pinBase = 0 ;
  512. verbose = printErrors ;
  513. // Get the extension extension name by finding the first colon
  514. p = extension ;
  515. while (*p != ':')
  516. {
  517. if (!*p) // ran out of characters
  518. {
  519. verbError ("%s: extension name not terminated by a colon", progName) ;
  520. return FALSE ;
  521. }
  522. ++p ;
  523. }
  524. *p++ = 0 ;
  525. if (!isdigit (*p))
  526. {
  527. verbError ("%s: pinBase number expected after extension name", progName) ;
  528. return FALSE ;
  529. }
  530. while (isdigit (*p))
  531. {
  532. if (pinBase > 1000000000)
  533. {
  534. verbError ("%s: pinBase too large", progName) ;
  535. return FALSE ;
  536. }
  537. pinBase = pinBase * 10 + (*p - '0') ;
  538. ++p ;
  539. }
  540. if (pinBase < 64)
  541. {
  542. verbError ("%s: pinBase (%d) too small. Minimum is 64.", progName, pinBase) ;
  543. return FALSE ;
  544. }
  545. // Search for extensions:
  546. for (extensionFn = extensionFunctions ; extensionFn->name != NULL ; ++extensionFn)
  547. {
  548. if (strcmp (extensionFn->name, extension) == 0)
  549. return extensionFn->function (progName, pinBase, p) ;
  550. }
  551. verbError ("%s: extension %s not found", progName, extension) ;
  552. return FALSE ;
  553. }