You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  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 "pcf8574.h"
  44. #include "pcf8591.h"
  45. #include "mcp3002.h"
  46. #include "mcp3004.h"
  47. #include "mcp4802.h"
  48. #include "mcp3422.h"
  49. #include "max31855.h"
  50. #include "max5322.h"
  51. #include "ads1115.h"
  52. #include "sn3218.h"
  53. #include "drcSerial.h"
  54. #include "wpiExtensions.h"
  55. extern int wiringPiDebug ;
  56. static int verbose ;
  57. static char errorMessage [1024] ;
  58. // Local structure to hold details
  59. struct extensionFunctionStruct
  60. {
  61. const char *name ;
  62. int (*function)(char *progName, int pinBase, char *params) ;
  63. } ;
  64. /*
  65. * verbError:
  66. * Convenient error handling
  67. *********************************************************************************
  68. */
  69. static void verbError (const char *message, ...)
  70. {
  71. va_list argp ;
  72. va_start (argp, message) ;
  73. vsnprintf (errorMessage, 1023, message, argp) ;
  74. va_end (argp) ;
  75. if (verbose)
  76. fprintf (stderr, "%s\n", errorMessage) ;
  77. }
  78. /*
  79. * extractInt:
  80. * Check & return an integer at the given location (prefixed by a :)
  81. *********************************************************************************
  82. */
  83. static char *extractInt (char *progName, char *p, int *num)
  84. {
  85. if (*p != ':')
  86. {
  87. verbError ("%s: colon expected", progName) ;
  88. return NULL ;
  89. }
  90. ++p ;
  91. if (!isdigit (*p))
  92. {
  93. verbError ("%s: digit expected", progName) ;
  94. return NULL ;
  95. }
  96. *num = strtol (p, NULL, 0) ;
  97. // Increment p, but we need to check for hex 0x
  98. if ((*p == '0') && (*(p + 1) == 'x'))
  99. p +=2 ;
  100. while (isxdigit (*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. * doExtensionAds1115:
  287. * Analog Input
  288. * ads1115:base:i2cAddr
  289. *********************************************************************************
  290. */
  291. static int doExtensionAds1115 (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. ads1115Setup (pinBase, i2c) ;
  302. return TRUE ;
  303. }
  304. /*
  305. * doExtensionPcf8591:
  306. * Analog IO
  307. * pcf8591:base:i2cAddr
  308. *********************************************************************************
  309. */
  310. static int doExtensionPcf8591 (char *progName, int pinBase, char *params)
  311. {
  312. int i2c ;
  313. if ((params = extractInt (progName, params, &i2c)) == NULL)
  314. return FALSE ;
  315. if ((i2c < 0x03) || (i2c > 0x77))
  316. {
  317. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  318. return FALSE ;
  319. }
  320. pcf8591Setup (pinBase, i2c) ;
  321. return TRUE ;
  322. }
  323. /*
  324. * doExtensionMax31855:
  325. * Analog IO
  326. * max31855:base:spiChan
  327. *********************************************************************************
  328. */
  329. static int doExtensionMax31855 (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. max31855Setup (pinBase, spi) ;
  340. return TRUE ;
  341. }
  342. /*
  343. * doExtensionMcp3002:
  344. * Analog IO
  345. * mcp3002:base:spiChan
  346. *********************************************************************************
  347. */
  348. static int doExtensionMcp3002 (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. mcp3002Setup (pinBase, spi) ;
  359. return TRUE ;
  360. }
  361. /*
  362. * doExtensionMcp3004:
  363. * Analog IO
  364. * mcp3004:base:spiChan
  365. *********************************************************************************
  366. */
  367. static int doExtensionMcp3004 (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. mcp3004Setup (pinBase, spi) ;
  378. return TRUE ;
  379. }
  380. /*
  381. * doExtensionMax5322:
  382. * Analog O
  383. * max5322:base:spiChan
  384. *********************************************************************************
  385. */
  386. static int doExtensionMax5322 (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. max5322Setup (pinBase, spi) ;
  397. return TRUE ;
  398. }
  399. /*
  400. * doExtensionMcp4802:
  401. * Analog IO
  402. * mcp4802:base:spiChan
  403. *********************************************************************************
  404. */
  405. static int doExtensionMcp4802 (char *progName, int pinBase, char *params)
  406. {
  407. int spi ;
  408. if ((params = extractInt (progName, params, &spi)) == NULL)
  409. return FALSE ;
  410. if ((spi < 0) || (spi > 1))
  411. {
  412. verbError ("%s: SPI channel (%d) out of range", progName, spi) ;
  413. return FALSE ;
  414. }
  415. mcp4802Setup (pinBase, spi) ;
  416. return TRUE ;
  417. }
  418. /*
  419. * doExtensionSn3218:
  420. * Analog Output (LED Driver)
  421. * sn3218:base
  422. *********************************************************************************
  423. */
  424. static int doExtensionSn3218 (char *progName, int pinBase, char *params)
  425. {
  426. sn3218Setup (pinBase) ;
  427. return TRUE ;
  428. }
  429. /*
  430. * doExtensionMcp3422:
  431. * Analog IO
  432. * mcp3422:base:i2cAddr
  433. *********************************************************************************
  434. */
  435. static int doExtensionMcp3422 (char *progName, int pinBase, char *params)
  436. {
  437. int i2c, sampleRate, gain ;
  438. if ((params = extractInt (progName, params, &i2c)) == NULL)
  439. return FALSE ;
  440. if ((i2c < 0x03) || (i2c > 0x77))
  441. {
  442. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  443. return FALSE ;
  444. }
  445. if ((params = extractInt (progName, params, &sampleRate)) == NULL)
  446. return FALSE ;
  447. if ((sampleRate < 0) || (sampleRate > 3))
  448. {
  449. verbError ("%s: sample rate (%d) out of range", progName, sampleRate) ;
  450. return FALSE ;
  451. }
  452. if ((params = extractInt (progName, params, &gain)) == NULL)
  453. return FALSE ;
  454. if ((gain < 0) || (gain > 3))
  455. {
  456. verbError ("%s: gain (%d) out of range", progName, gain) ;
  457. return FALSE ;
  458. }
  459. mcp3422Setup (pinBase, i2c, sampleRate, gain) ;
  460. return TRUE ;
  461. }
  462. /*
  463. * doExtensionDrcS:
  464. * Interface to a DRC Serial system
  465. * drcs:base:pins:serialPort:baud
  466. *********************************************************************************
  467. */
  468. static int doExtensionDrcS (char *progName, int pinBase, char *params)
  469. {
  470. char *port ;
  471. int pins, baud ;
  472. if ((params = extractInt (progName, params, &pins)) == NULL)
  473. return FALSE ;
  474. if ((pins < 1) || (pins > 100))
  475. {
  476. verbError ("%s: pins (%d) out of range (2-100)", progName, pins) ;
  477. return FALSE ;
  478. }
  479. if ((params = extractStr (progName, params, &port)) == NULL)
  480. return FALSE ;
  481. if (strlen (port) == 0)
  482. {
  483. verbError ("%s: serial port device name required", progName) ;
  484. return FALSE ;
  485. }
  486. if ((params = extractInt (progName, params, &baud)) == NULL)
  487. return FALSE ;
  488. if ((baud < 1) || (baud > 4000000))
  489. {
  490. verbError ("%s: baud rate (%d) out of range", progName, baud) ;
  491. return FALSE ;
  492. }
  493. drcSetupSerial (pinBase, pins, port, baud) ;
  494. return TRUE ;
  495. }
  496. /*
  497. * Function list
  498. *********************************************************************************
  499. */
  500. static struct extensionFunctionStruct extensionFunctions [] =
  501. {
  502. { "mcp23008", &doExtensionMcp23008 },
  503. { "mcp23016", &doExtensionMcp23016 },
  504. { "mcp23017", &doExtensionMcp23017 },
  505. { "mcp23s08", &doExtensionMcp23s08 },
  506. { "mcp23s17", &doExtensionMcp23s17 },
  507. { "sr595", &doExtensionSr595 },
  508. { "pcf8574", &doExtensionPcf8574 },
  509. { "pcf8591", &doExtensionPcf8591 },
  510. { "mcp3002", &doExtensionMcp3002 },
  511. { "mcp3004", &doExtensionMcp3004 },
  512. { "mcp4802", &doExtensionMcp4802 },
  513. { "mcp3422", &doExtensionMcp3422 },
  514. { "max31855", &doExtensionMax31855 },
  515. { "ads1115", &doExtensionAds1115 },
  516. { "max5322", &doExtensionMax5322 },
  517. { "sn3218", &doExtensionSn3218 },
  518. { "drcs", &doExtensionDrcS },
  519. { NULL, NULL },
  520. } ;
  521. /*
  522. * loadWPiExtension:
  523. * Load in a wiringPi extension
  524. * The extensionData always starts with the name, a colon then the pinBase
  525. * number. Other parameters after that are decoded by the module in question.
  526. *********************************************************************************
  527. */
  528. int loadWPiExtension (char *progName, char *extensionData, int printErrors)
  529. {
  530. char *p ;
  531. char *extension = extensionData ;
  532. struct extensionFunctionStruct *extensionFn ;
  533. unsigned pinBase = 0 ;
  534. verbose = printErrors ;
  535. // Get the extension name by finding the first colon
  536. p = extension ;
  537. while (*p != ':')
  538. {
  539. if (!*p) // ran out of characters
  540. {
  541. verbError ("%s: extension name not terminated by a colon", progName) ;
  542. return FALSE ;
  543. }
  544. ++p ;
  545. }
  546. *p++ = 0 ;
  547. // Simple ATOI code
  548. if (!isdigit (*p))
  549. {
  550. verbError ("%s: decimal pinBase number expected after extension name", progName) ;
  551. return FALSE ;
  552. }
  553. while (isdigit (*p))
  554. {
  555. if (pinBase > 2147483647) // 2^31-1 ... Lets be realistic here...
  556. {
  557. verbError ("%s: pinBase too large", progName) ;
  558. return FALSE ;
  559. }
  560. pinBase = pinBase * 10 + (*p - '0') ;
  561. ++p ;
  562. }
  563. if (pinBase < 64)
  564. {
  565. verbError ("%s: pinBase (%d) too small. Minimum is 64.", progName, pinBase) ;
  566. return FALSE ;
  567. }
  568. // Search for extensions:
  569. for (extensionFn = extensionFunctions ; extensionFn->name != NULL ; ++extensionFn)
  570. {
  571. if (strcmp (extensionFn->name, extension) == 0)
  572. return extensionFn->function (progName, pinBase, p) ;
  573. }
  574. verbError ("%s: extension %s not found", progName, extension) ;
  575. return FALSE ;
  576. }