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.
 
 
 
 
 

929 lines
20 KiB

  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://github.com/WiringPi/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 "drcNet.h"
  55. #include "../wiringPiD/drcNetCmd.h"
  56. #include "pseudoPins.h"
  57. #include "bmp180.h"
  58. #include "htu21d.h"
  59. #include "ds18b20.h"
  60. #include "rht03.h"
  61. #include "wpiExtensions.h"
  62. extern int wiringPiDebug ;
  63. static int verbose ;
  64. static char errorMessage [1024] ;
  65. // Local structure to hold details
  66. struct extensionFunctionStruct
  67. {
  68. const char *name ;
  69. int (*function)(char *progName, int pinBase, char *params) ;
  70. } ;
  71. /*
  72. * verbError:
  73. * Convenient error handling
  74. *********************************************************************************
  75. */
  76. static void verbError (const char *message, ...)
  77. {
  78. va_list argp ;
  79. va_start (argp, message) ;
  80. vsnprintf (errorMessage, 1023, message, argp) ;
  81. va_end (argp) ;
  82. if (verbose)
  83. fprintf (stderr, "%s\n", errorMessage) ;
  84. }
  85. /*
  86. * extractInt:
  87. * Check & return an integer at the given location (prefixed by a :)
  88. *********************************************************************************
  89. */
  90. static char *extractInt (char *progName, char *p, int *num)
  91. {
  92. if (*p != ':')
  93. {
  94. verbError ("%s: colon expected", progName) ;
  95. return NULL ;
  96. }
  97. ++p ;
  98. if (!isdigit (*p))
  99. {
  100. verbError ("%s: digit expected", progName) ;
  101. return NULL ;
  102. }
  103. *num = strtol (p, NULL, 0) ;
  104. // Increment p, but we need to check for hex 0x
  105. if ((*p == '0') && (*(p + 1) == 'x'))
  106. p +=2 ;
  107. while (isxdigit (*p))
  108. ++p ;
  109. return p ;
  110. }
  111. /*
  112. * extractStr:
  113. * Check & return a string at the given location (prefixed by a :)
  114. * Note: The string can be enclosed in []'s to escape colons. This is
  115. * so we can handle IPv6 addresses which contain colons and the []'s is
  116. * a common way to prepresent them.
  117. *********************************************************************************
  118. */
  119. static char *extractStr (char *progName, char *p, char **str)
  120. {
  121. char *q, *r ;
  122. int quoted = FALSE ;
  123. if (*p != ':')
  124. {
  125. verbError ("%s: colon expected", progName) ;
  126. return NULL ;
  127. }
  128. ++p ;
  129. if (*p == '[')
  130. {
  131. quoted = TRUE ;
  132. ++p ;
  133. }
  134. if (!isprint (*p)) // Is this needed?
  135. {
  136. verbError ("%s: character expected", progName) ;
  137. return NULL ;
  138. }
  139. q = p ;
  140. if (quoted)
  141. {
  142. while ((*q != 0) && (*q != ']'))
  143. ++q ;
  144. }
  145. else
  146. {
  147. while ((*q != 0) && (*q != ':'))
  148. ++q ;
  149. }
  150. *str = r = calloc (q - p + 2, 1) ; // Zeros it
  151. while (p != q)
  152. *r++ = *p++ ;
  153. if (quoted) // Skip over the ] to the :
  154. ++p ;
  155. return p ;
  156. }
  157. /*
  158. * doExtensionMcp23008:
  159. * MCP23008 - 8-bit I2C GPIO expansion chip
  160. * mcp23002:base:i2cAddr
  161. *********************************************************************************
  162. */
  163. static int doExtensionMcp23008 (char *progName, int pinBase, char *params)
  164. {
  165. int i2c ;
  166. if ((params = extractInt (progName, params, &i2c)) == NULL)
  167. return FALSE ;
  168. if ((i2c < 0x01) || (i2c > 0x77))
  169. {
  170. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  171. return FALSE ;
  172. }
  173. mcp23008Setup (pinBase, i2c) ;
  174. return TRUE ;
  175. }
  176. /*
  177. * doExtensionMcp23016:
  178. * MCP230016- 16-bit I2C GPIO expansion chip
  179. * mcp23016:base:i2cAddr
  180. *********************************************************************************
  181. */
  182. static int doExtensionMcp23016 (char *progName, int pinBase, char *params)
  183. {
  184. int i2c ;
  185. if ((params = extractInt (progName, params, &i2c)) == NULL)
  186. return FALSE ;
  187. if ((i2c < 0x03) || (i2c > 0x77))
  188. {
  189. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  190. return FALSE ;
  191. }
  192. mcp23016Setup (pinBase, i2c) ;
  193. return TRUE ;
  194. }
  195. /*
  196. * doExtensionMcp23017:
  197. * MCP230017- 16-bit I2C GPIO expansion chip
  198. * mcp23017:base:i2cAddr
  199. *********************************************************************************
  200. */
  201. static int doExtensionMcp23017 (char *progName, int pinBase, char *params)
  202. {
  203. int i2c ;
  204. if ((params = extractInt (progName, params, &i2c)) == NULL)
  205. return FALSE ;
  206. if ((i2c < 0x03) || (i2c > 0x77))
  207. {
  208. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  209. return FALSE ;
  210. }
  211. mcp23017Setup (pinBase, i2c) ;
  212. return TRUE ;
  213. }
  214. /*
  215. * doExtensionMcp23s08:
  216. * MCP23s08 - 8-bit SPI GPIO expansion chip
  217. * mcp23s08:base:spi:port
  218. *********************************************************************************
  219. */
  220. static int doExtensionMcp23s08 (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. mcp23s08Setup (pinBase, spi, port) ;
  238. return TRUE ;
  239. }
  240. /*
  241. * doExtensionMcp23s17:
  242. * MCP23s17 - 16-bit SPI GPIO expansion chip
  243. * mcp23s17:base:spi:port
  244. *********************************************************************************
  245. */
  246. static int doExtensionMcp23s17 (char *progName, int pinBase, char *params)
  247. {
  248. int spi, port ;
  249. if ((params = extractInt (progName, params, &spi)) == NULL)
  250. return FALSE ;
  251. if ((spi < 0) || (spi > 1))
  252. {
  253. verbError ("%s: SPI address (%d) out of range", progName, spi) ;
  254. return FALSE ;
  255. }
  256. if ((params = extractInt (progName, params, &port)) == NULL)
  257. return FALSE ;
  258. if ((port < 0) || (port > 7))
  259. {
  260. verbError ("%s: port address (%d) out of range", progName, port) ;
  261. return FALSE ;
  262. }
  263. mcp23s17Setup (pinBase, spi, port) ;
  264. return TRUE ;
  265. }
  266. /*
  267. * doExtensionSr595:
  268. * Shift Register 74x595
  269. * sr595:base:pins:data:clock:latch
  270. *********************************************************************************
  271. */
  272. static int doExtensionSr595 (char *progName, int pinBase, char *params)
  273. {
  274. int pins, data, clock, latch ;
  275. // Extract pins
  276. if ((params = extractInt (progName, params, &pins)) == NULL)
  277. return FALSE ;
  278. if ((pins < 8) || (pins > 32))
  279. {
  280. verbError ("%s: pin count (%d) out of range - 8-32 expected.", progName, pins) ;
  281. return FALSE ;
  282. }
  283. if ((params = extractInt (progName, params, &data)) == NULL)
  284. return FALSE ;
  285. if ((params = extractInt (progName, params, &clock)) == NULL)
  286. return FALSE ;
  287. if ((params = extractInt (progName, params, &latch)) == NULL)
  288. return FALSE ;
  289. sr595Setup (pinBase, pins, data, clock, latch) ;
  290. return TRUE ;
  291. }
  292. /*
  293. * doExtensionPcf8574:
  294. * Digital IO (Crude!)
  295. * pcf8574:base:i2cAddr
  296. *********************************************************************************
  297. */
  298. static int doExtensionPcf8574 (char *progName, int pinBase, char *params)
  299. {
  300. int i2c ;
  301. if ((params = extractInt (progName, params, &i2c)) == NULL)
  302. return FALSE ;
  303. if ((i2c < 0x03) || (i2c > 0x77))
  304. {
  305. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  306. return FALSE ;
  307. }
  308. pcf8574Setup (pinBase, i2c) ;
  309. return TRUE ;
  310. }
  311. /*
  312. * doExtensionAds1115:
  313. * Analog Input
  314. * ads1115:base:i2cAddr
  315. *********************************************************************************
  316. */
  317. static int doExtensionAds1115 (char *progName, int pinBase, char *params)
  318. {
  319. int i2c ;
  320. if ((params = extractInt (progName, params, &i2c)) == NULL)
  321. return FALSE ;
  322. if ((i2c < 0x03) || (i2c > 0x77))
  323. {
  324. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  325. return FALSE ;
  326. }
  327. ads1115Setup (pinBase, i2c) ;
  328. return TRUE ;
  329. }
  330. /*
  331. * doExtensionPcf8591:
  332. * Analog IO
  333. * pcf8591:base:i2cAddr
  334. *********************************************************************************
  335. */
  336. static int doExtensionPcf8591 (char *progName, int pinBase, char *params)
  337. {
  338. int i2c ;
  339. if ((params = extractInt (progName, params, &i2c)) == NULL)
  340. return FALSE ;
  341. if ((i2c < 0x03) || (i2c > 0x77))
  342. {
  343. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  344. return FALSE ;
  345. }
  346. pcf8591Setup (pinBase, i2c) ;
  347. return TRUE ;
  348. }
  349. /*
  350. * doExtensionPseudoPins:
  351. * 64 Memory resident pseudo pins
  352. * pseudoPins:base
  353. *********************************************************************************
  354. */
  355. static int doExtensionPseudoPins (UNU char *progName, int pinBase, UNU char *params)
  356. {
  357. pseudoPinsSetup (pinBase) ;
  358. return TRUE ;
  359. }
  360. /*
  361. * doExtensionBmp180:
  362. * Analog Temp + Pressure
  363. * bmp180:base
  364. *********************************************************************************
  365. */
  366. static int doExtensionBmp180 (UNU char *progName, int pinBase, UNU char *params)
  367. {
  368. bmp180Setup (pinBase) ;
  369. return TRUE ;
  370. }
  371. /*
  372. * doExtensionHtu21d:
  373. * Analog humidity + Pressure
  374. * htu21d:base
  375. *********************************************************************************
  376. */
  377. static int doExtensionHtu21d (UNU char *progName, int pinBase, UNU char *params)
  378. {
  379. htu21dSetup (pinBase) ;
  380. return TRUE ;
  381. }
  382. /*
  383. * doExtensionDs18b20:
  384. * 1-Wire Temperature
  385. * htu21d:base:serialNum
  386. *********************************************************************************
  387. */
  388. static int doExtensionDs18b20 (char *progName, int pinBase, char *params)
  389. {
  390. char *serialNum ;
  391. if ((params = extractStr (progName, params, &serialNum)) == NULL)
  392. return FALSE ;
  393. return ds18b20Setup (pinBase, serialNum) ;
  394. }
  395. /*
  396. * doExtensionRht03:
  397. * Maxdetect 1-Wire Temperature & Humidity
  398. * rht03:base:piPin
  399. *********************************************************************************
  400. */
  401. static int doExtensionRht03 (char *progName, int pinBase, char *params)
  402. {
  403. int piPin ;
  404. if ((params = extractInt (progName, params, &piPin)) == NULL)
  405. return FALSE ;
  406. return rht03Setup (pinBase, piPin) ;
  407. }
  408. /*
  409. * doExtensionMax31855:
  410. * Analog IO
  411. * max31855:base:spiChan
  412. *********************************************************************************
  413. */
  414. static int doExtensionMax31855 (char *progName, int pinBase, char *params)
  415. {
  416. int spi ;
  417. if ((params = extractInt (progName, params, &spi)) == NULL)
  418. return FALSE ;
  419. if ((spi < 0) || (spi > 1))
  420. {
  421. verbError ("%s: SPI channel (%d) out of range", progName, spi) ;
  422. return FALSE ;
  423. }
  424. max31855Setup (pinBase, spi) ;
  425. return TRUE ;
  426. }
  427. /*
  428. * doExtensionMcp3002:
  429. * Analog IO
  430. * mcp3002:base:spiChan
  431. *********************************************************************************
  432. */
  433. static int doExtensionMcp3002 (char *progName, int pinBase, char *params)
  434. {
  435. int spi ;
  436. if ((params = extractInt (progName, params, &spi)) == NULL)
  437. return FALSE ;
  438. if ((spi < 0) || (spi > 1))
  439. {
  440. verbError ("%s: SPI channel (%d) out of range", progName, spi) ;
  441. return FALSE ;
  442. }
  443. mcp3002Setup (pinBase, spi) ;
  444. return TRUE ;
  445. }
  446. /*
  447. * doExtensionMcp3004:
  448. * Analog IO
  449. * mcp3004:base:spiChan
  450. *********************************************************************************
  451. */
  452. static int doExtensionMcp3004 (char *progName, int pinBase, char *params)
  453. {
  454. int spi ;
  455. if ((params = extractInt (progName, params, &spi)) == NULL)
  456. return FALSE ;
  457. if ((spi < 0) || (spi > 1))
  458. {
  459. verbError ("%s: SPI channel (%d) out of range", progName, spi) ;
  460. return FALSE ;
  461. }
  462. mcp3004Setup (pinBase, spi) ;
  463. return TRUE ;
  464. }
  465. /*
  466. * doExtensionMax5322:
  467. * Analog O
  468. * max5322:base:spiChan
  469. *********************************************************************************
  470. */
  471. static int doExtensionMax5322 (char *progName, int pinBase, char *params)
  472. {
  473. int spi ;
  474. if ((params = extractInt (progName, params, &spi)) == NULL)
  475. return FALSE ;
  476. if ((spi < 0) || (spi > 1))
  477. {
  478. verbError ("%s: SPI channel (%d) out of range", progName, spi) ;
  479. return FALSE ;
  480. }
  481. max5322Setup (pinBase, spi) ;
  482. return TRUE ;
  483. }
  484. /*
  485. * doExtensionMcp4802:
  486. * Analog IO
  487. * mcp4802:base:spiChan
  488. *********************************************************************************
  489. */
  490. static int doExtensionMcp4802 (char *progName, int pinBase, char *params)
  491. {
  492. int spi ;
  493. if ((params = extractInt (progName, params, &spi)) == NULL)
  494. return FALSE ;
  495. if ((spi < 0) || (spi > 1))
  496. {
  497. verbError ("%s: SPI channel (%d) out of range", progName, spi) ;
  498. return FALSE ;
  499. }
  500. mcp4802Setup (pinBase, spi) ;
  501. return TRUE ;
  502. }
  503. /*
  504. * doExtensionSn3218:
  505. * Analog Output (LED Driver)
  506. * sn3218:base
  507. *********************************************************************************
  508. */
  509. static int doExtensionSn3218 (UNU char *progName, int pinBase, UNU char *params)
  510. {
  511. sn3218Setup (pinBase) ;
  512. return TRUE ;
  513. }
  514. /*
  515. * doExtensionMcp3422:
  516. * Analog IO
  517. * mcp3422:base:i2cAddr
  518. *********************************************************************************
  519. */
  520. static int doExtensionMcp3422 (char *progName, int pinBase, char *params)
  521. {
  522. int i2c, sampleRate, gain ;
  523. if ((params = extractInt (progName, params, &i2c)) == NULL)
  524. return FALSE ;
  525. if ((i2c < 0x03) || (i2c > 0x77))
  526. {
  527. verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ;
  528. return FALSE ;
  529. }
  530. if ((params = extractInt (progName, params, &sampleRate)) == NULL)
  531. return FALSE ;
  532. if ((sampleRate < 0) || (sampleRate > 3))
  533. {
  534. verbError ("%s: sample rate (%d) out of range", progName, sampleRate) ;
  535. return FALSE ;
  536. }
  537. if ((params = extractInt (progName, params, &gain)) == NULL)
  538. return FALSE ;
  539. if ((gain < 0) || (gain > 3))
  540. {
  541. verbError ("%s: gain (%d) out of range", progName, gain) ;
  542. return FALSE ;
  543. }
  544. mcp3422Setup (pinBase, i2c, sampleRate, gain) ;
  545. return TRUE ;
  546. }
  547. /*
  548. * doExtensionDrcS:
  549. * Interface to a DRC Serial system
  550. * drcs:base:pins:serialPort:baud
  551. *********************************************************************************
  552. */
  553. static int doExtensionDrcS (char *progName, int pinBase, char *params)
  554. {
  555. char *port ;
  556. int pins, baud ;
  557. if ((params = extractInt (progName, params, &pins)) == NULL)
  558. return FALSE ;
  559. if ((pins < 1) || (pins > 1000))
  560. {
  561. verbError ("%s: pins (%d) out of range (2-1000)", progName, pins) ;
  562. return FALSE ;
  563. }
  564. if ((params = extractStr (progName, params, &port)) == NULL)
  565. return FALSE ;
  566. if (strlen (port) == 0)
  567. {
  568. verbError ("%s: serial port device name required", progName) ;
  569. return FALSE ;
  570. }
  571. if ((params = extractInt (progName, params, &baud)) == NULL)
  572. return FALSE ;
  573. if ((baud < 1) || (baud > 4000000))
  574. {
  575. verbError ("%s: baud rate (%d) out of range", progName, baud) ;
  576. return FALSE ;
  577. }
  578. drcSetupSerial (pinBase, pins, port, baud) ;
  579. return TRUE ;
  580. }
  581. /*
  582. * doExtensionDrcNet:
  583. * Interface to a DRC Network system
  584. * drcn:base:pins:ipAddress:port:password
  585. *********************************************************************************
  586. */
  587. static int doExtensionDrcNet (char *progName, int pinBase, char *params)
  588. {
  589. int pins ;
  590. char *ipAddress, *port, *password ;
  591. char pPort [1024] ;
  592. if ((params = extractInt (progName, params, &pins)) == NULL)
  593. return FALSE ;
  594. if ((pins < 1) || (pins > 1000))
  595. {
  596. verbError ("%s: pins (%d) out of range (2-1000)", progName, pins) ;
  597. return FALSE ;
  598. }
  599. if ((params = extractStr (progName, params, &ipAddress)) == NULL)
  600. return FALSE ;
  601. if (strlen (ipAddress) == 0)
  602. {
  603. verbError ("%s: ipAddress required", progName) ;
  604. return FALSE ;
  605. }
  606. if ((params = extractStr (progName, params, &port)) == NULL)
  607. return FALSE ;
  608. if (strlen (port) == 0)
  609. {
  610. sprintf (pPort, "%d", DEFAULT_SERVER_PORT) ;
  611. port = pPort ;
  612. }
  613. if ((params = extractStr (progName, params, &password)) == NULL)
  614. return FALSE ;
  615. if (strlen (password) == 0)
  616. {
  617. verbError ("%s: password required", progName) ;
  618. return FALSE ;
  619. }
  620. return drcSetupNet (pinBase, pins, ipAddress, port, password) ;
  621. }
  622. /*
  623. * Function list
  624. *********************************************************************************
  625. */
  626. static struct extensionFunctionStruct extensionFunctions [] =
  627. {
  628. { "mcp23008", &doExtensionMcp23008 },
  629. { "mcp23016", &doExtensionMcp23016 },
  630. { "mcp23017", &doExtensionMcp23017 },
  631. { "mcp23s08", &doExtensionMcp23s08 },
  632. { "mcp23s17", &doExtensionMcp23s17 },
  633. { "sr595", &doExtensionSr595 },
  634. { "pcf8574", &doExtensionPcf8574 },
  635. { "pcf8591", &doExtensionPcf8591 },
  636. { "bmp180", &doExtensionBmp180 },
  637. { "pseudoPins", &doExtensionPseudoPins },
  638. { "htu21d", &doExtensionHtu21d },
  639. { "ds18b20", &doExtensionDs18b20 },
  640. { "rht03", &doExtensionRht03 },
  641. { "mcp3002", &doExtensionMcp3002 },
  642. { "mcp3004", &doExtensionMcp3004 },
  643. { "mcp4802", &doExtensionMcp4802 },
  644. { "mcp3422", &doExtensionMcp3422 },
  645. { "max31855", &doExtensionMax31855 },
  646. { "ads1115", &doExtensionAds1115 },
  647. { "max5322", &doExtensionMax5322 },
  648. { "sn3218", &doExtensionSn3218 },
  649. { "drcs", &doExtensionDrcS },
  650. { "drcn", &doExtensionDrcNet },
  651. { NULL, NULL },
  652. } ;
  653. /*
  654. * loadWPiExtension:
  655. * Load in a wiringPi extension
  656. * The extensionData always starts with the name, a colon then the pinBase
  657. * number. Other parameters after that are decoded by the module in question.
  658. *********************************************************************************
  659. */
  660. int loadWPiExtension (char *progName, char *extensionData, int printErrors)
  661. {
  662. char *p ;
  663. char *extension = extensionData ;
  664. struct extensionFunctionStruct *extensionFn ;
  665. int pinBase = 0 ;
  666. verbose = printErrors ;
  667. // Get the extension name by finding the first colon
  668. p = extension ;
  669. while (*p != ':')
  670. {
  671. if (!*p) // ran out of characters
  672. {
  673. verbError ("%s: extension name not terminated by a colon", progName) ;
  674. return FALSE ;
  675. }
  676. ++p ;
  677. }
  678. *p++ = 0 ;
  679. // Simple ATOI code
  680. if (!isdigit (*p))
  681. {
  682. verbError ("%s: decimal pinBase number expected after extension name", progName) ;
  683. return FALSE ;
  684. }
  685. while (isdigit (*p))
  686. {
  687. if (pinBase > 2147483647) // 2^31-1 ... Lets be realistic here...
  688. {
  689. verbError ("%s: pinBase too large", progName) ;
  690. return FALSE ;
  691. }
  692. pinBase = pinBase * 10 + (*p - '0') ;
  693. ++p ;
  694. }
  695. if (pinBase < 64)
  696. {
  697. verbError ("%s: pinBase (%d) too small. Minimum is 64.", progName, pinBase) ;
  698. return FALSE ;
  699. }
  700. // Search for extensions:
  701. for (extensionFn = extensionFunctions ; extensionFn->name != NULL ; ++extensionFn)
  702. {
  703. if (strcmp (extensionFn->name, extension) == 0)
  704. return extensionFn->function (progName, pinBase, p) ;
  705. }
  706. fprintf (stderr, "%s: extension %s not found", progName, extension) ;
  707. return FALSE ;
  708. }