armbianio.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. //
  2. // Armbian IO library
  3. //
  4. // Copyright (c) 2017 BitBank Software, Inc.
  5. // written by Larry Bank
  6. // email: bitbank@pobox.com
  7. // Project started 11/12/2017
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU 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. // This program 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 General Public License for more details.
  18. //
  19. // You should have received a copy of the GNU General Public License
  20. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. //
  22. #include <unistd.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <stdint.h>
  27. #include <fcntl.h>
  28. #include <sys/ioctl.h>
  29. #include <linux/types.h>
  30. #include "armbianio.h"
  31. #include <linux/spi/spidev.h>
  32. #include <linux/i2c-dev.h>
  33. #include <pthread.h>
  34. #include <poll.h>
  35. static struct spi_ioc_transfer xfer;
  36. // Maximum header pins for all supported boards
  37. #define MAX_PINS IR_PIN+1
  38. static int iPinHandles[MAX_PINS]; // keep file handles open for GPIO access
  39. static AIOCALLBACK cbList[MAX_PINS];
  40. static AIOIRCALLBACK cbIRList[MAX_PINS];
  41. //
  42. // The following are lists which translate pin numbers into the GPIO numbers
  43. // used by the different boards. The first entry (0) is for the on-board
  44. // button (if present). A -1 indicates that the pin is not available to use
  45. // as a GPIO (e.g. +5V, GND, etc). The numbering normally starts with the 3.3v
  46. // pin as 1 and the 5V pin as 2. The TTY header comes after the last GPIO pin
  47. // and is numbered from the pin closest to the edge of the board. On the
  48. // Orange Pi Zero, this means that GND is pin 27, RX is 28 and TX is 29. The
  49. // reason these are included is because they are multiplexed inside the SoC
  50. // and can be used for GPIOs as well.
  51. //
  52. // Le potato
  53. static int ipotatoPins[] = {-1,-1,-1,5,-1,4,-1,108,101,-1,
  54. 102,-1,6,9,-1,110,103,-1,104,97,
  55. -1,98,89,100,99,-1,90,85,86,106,
  56. -1,107,105,95,-1,96,91,94,92,-1,
  57. 93};
  58. // Banana Pi M2 Zero
  59. static int iBPIZPins[] = {355,-1,-1,12,-1,11,-1,6,13,-1,
  60. 14,1,110,0,-1,3,15,-1,68,64,
  61. -1,65,2,66,67,-1,71,19,18,7,
  62. -1,8,354,9,-1,10,356,17,21,-1,
  63. 20};
  64. // Raspberry Pi
  65. static int iRPIPins[] = {-1,-1,-1,2,-1,3,-1,4,14,-1,
  66. 15,17,18,27,-1,22,23,-1,24,10,
  67. -1,9,25,11,8,-1,7,0,1,5,
  68. -1,6,12,13,-1,19,16,26,20,-1,
  69. 21};
  70. static int iWiringPiPins[] = {-1,-1,-1,8,-1,9,-1,7,
  71. 15,-1,16,0,1,2,-1,3,
  72. 4,-1,5,12,-1,13,6,14,
  73. 10,-1,11,30,31,21,-1,22,
  74. 26,23,-1,24,27,25,28,-1,
  75. 29};
  76. // Orange Pi Zero Plus
  77. static int iOPIZPPins[] = {-1,-1,-1,12,-1,11,-1,6,198,-1,
  78. 199,1,7,0,-1,3,19,-1,18,15,
  79. -1,16,2,14,13,-1,10,-1,5,4}; // last 3 pins are TTY header
  80. // Orange Pi Zero Plus 2
  81. static int iOPIZP2ins[] = {-1,-1,-1,12,-1,11,-1,6,0,-1,
  82. 1,352,107,353,-1,3,19,-1,18,-1,
  83. -1,-1,2,14,13,-1,110,-1,5,4}; // last 3 pins are TTY header
  84. // Orange Pi One
  85. static int iOPI1Pins[] = {355,-1,-1,12,-1,11,-1,6,13,-1,
  86. 14,1,110,0,-1,3,68,-1,71,64,
  87. -1,65,2,66,67,-1,21,19,18,7,
  88. -1,8,200,9,-1,10,201,20,198,-1
  89. ,199,4,5,-1}; // last 3 pins are TTY header
  90. // Orange Pi Zero
  91. static int iOPIZPins[] = {-1,-1,-1,12,-1,11,-1,6,198,-1,
  92. 199,1,7,0,-1,3,19,-1,18,15,
  93. -1,16,2,14,13,-1,10,-1,5,4}; // last 3 pins are TTY header
  94. // NanoPi Duo
  95. static int iNPDPins[] = {355,5,-1,4,-1,-1,-1,11,-1,12,
  96. 363,13,203,14,-1,16,-1,15,-1,199,
  97. -1,198,-1,-1,-1,-1,-1,-1,-1,-1,
  98. -1,-1,-1};
  99. // NanoPi 2
  100. static int iNP2Pins[] = {0,-1,-1,99,-1,98,-1,32+28,96+21,-1,
  101. 96+17,32+29,32+26,32+30,-1,32+31,64+14,-1,32+27,64+31,
  102. -1,96+0,96+1,64+29,64+30,-1,64+13,103,102,64+8,
  103. -1,64+9,64+28,64+10,-1,64+12,64+7,64+11,162,-1,
  104. 163};
  105. // NanoPi K2
  106. static int iNPK2Pins[] = {3,-1,-1,205,-1,206,-1,211,102,-1,
  107. 225,212,227,213,-1,214,226,-1,215,216,
  108. -1,218,217,220,219,-1,221,207,208,222,
  109. -1,127,223,155,-1,252,-1,-1,-1,-1,
  110. -1};
  111. // NanoPi Neo & NanoPi Air & NanoPi Neo 2
  112. static int iNPNPins[] = {-1,-1,-1,12,-1,11,-1,203,198,-1,
  113. 199,0,6,2,-1,3,200,-1,201,64,
  114. -1,65,1,66,67,-1,-1,-1,-1,-1,
  115. 363,17,-1,-1,-1,-1,-1,-1,-1,4,
  116. 5};
  117. // NanoPi M4
  118. static int iNPM4Pins[] = {-1,-1,-1,-1,-1,-1,-1,32,145,-1,144,
  119. 33,50,35,-1,36,54,-1,55,-1,-1,
  120. -1,56,-1,-1,-1,149,-1,-1,-1,
  121. -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
  122. // Tinkerboard
  123. static int iTinkerPins[] = {-1,-1,-1,252,-1,253,-1,17,161,-1,
  124. 160,164,184,166,-1,167,162,-1,163,257,
  125. -1,256,171,254,255,-1,251,233,234,165,
  126. -1,168,239,238,-1,185,223,224,187,-1,
  127. 188};
  128. static int *iPinLists[] = {ipotatoPins, iBPIZPins, iRPIPins, iOPIZPPins, iOPIZP2ins, iOPIZPins, iOPI1Pins, iOPI1Pins, iNPDPins, iNP2Pins, iNPK2Pins, iNPNPins, iNPNPins, iNPNPins, iNPM4Pins, iNPM4Pins, iTinkerPins};
  129. static const char *szBoardNames[] = {"Le potato\n","Banana Pi M2 Zero\n","Raspberry Pi","Orange Pi Zero Plus\n","Orange Pi Zero Plus 2\n","Orange Pi Zero\n","Orange Pi Lite\n","Orange Pi One\n","NanoPi Duo\n", "NanoPi 2\n", "Nanopi K2\n", "NanoPi Neo\n", "NanoPi Air\n", "NanoPi Neo 2\n", "NanoPi M4\n", "NanoPi M4V2\n", "Tinkerboard\n",NULL};
  130. static int iBoardType;
  131. static int iPinCount[] = {40,40,40,29,29,29,43,43,32,40,40,40,40,40,40, 41,41}; // number of pins in the header
  132. // GPIO number of on-board IR receiver
  133. static int iIR_GPIO[] = {7, 0, 0, 363, 363, 363, 363, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  134. //
  135. // Close any open handles to GPIO pins and
  136. // 'unexport' them
  137. //
  138. void AIOShutdown(void)
  139. {
  140. int i;
  141. for (i=0; i<MAX_PINS; i++) // try to close/release all open GPIO pins
  142. {
  143. AIORemoveGPIO(i);
  144. }
  145. } /* AIOShutdown() */
  146. //
  147. // Initialize the ArmbianIO library
  148. // Convenience function calls AIOInitBoard with NULL
  149. //
  150. int AIOInit(void)
  151. {
  152. return AIOInitBoard(NULL);
  153. }
  154. //
  155. // Initialize the ArmbianIO library
  156. // Determines the board type (name) and initializes the 'key' if present
  157. //
  158. int AIOInitBoard(const char *pBoardName)
  159. {
  160. FILE *ihandle;
  161. char szTemp[256];
  162. int i;
  163. // Determine what board we're running on to know which GPIO
  164. // pin number table to use
  165. szTemp[0] = 0;
  166. if (pBoardName)
  167. {
  168. strcpy(szTemp, pBoardName);
  169. }
  170. else
  171. {
  172. ihandle = fopen("/run/machine.id", "rb");
  173. if (ihandle != NULL)
  174. {
  175. i = fread(szTemp, 1, 255, ihandle);
  176. fclose(ihandle);
  177. szTemp[i] = 0; // make sure it's zero terminated
  178. }
  179. }
  180. // see if the board name matches known names
  181. i = 0;
  182. iBoardType = 2;
  183. while (szBoardNames[i] != NULL)
  184. {
  185. if (strcmp(szBoardNames[i], szTemp) == 0) // found it!
  186. {
  187. iBoardType = i;
  188. break;
  189. }
  190. i++;
  191. }
  192. if (iBoardType == -1) // not found
  193. {
  194. fprintf(stderr, "Unrecognized board type, aborting...\n");
  195. return 0;
  196. }
  197. // Initialize all GPIO file system handles to -1 to start
  198. memset(iPinHandles, -1, sizeof(iPinHandles));
  199. // Try to activate the GPIO input for the key/button (if there is one)
  200. AIOAddGPIO(0, GPIO_IN);
  201. return 1; // success
  202. } /* AIOInit() */
  203. //
  204. // Boolean indicating if the current PCB has an on-board IR receiver module
  205. //
  206. int AIOHasIR(void)
  207. {
  208. if (iBoardType != -1)
  209. {
  210. return (iIR_GPIO[iBoardType] != 0);
  211. }
  212. return 0;
  213. } /* AIOHasIR() */
  214. //
  215. // Boolean indicating if the current PCB has a button/key on it
  216. //
  217. int AIOHasButton(void)
  218. {
  219. int *pPins;
  220. if (iBoardType != -1)
  221. {
  222. pPins = iPinLists[iBoardType];
  223. return (pPins[0] != -1); // if the GPIO number at index 0 is valid
  224. }
  225. return 0;
  226. } /* AIOHasButton() */
  227. //
  228. // Read the boolean value of the key/button on the board
  229. // A 0 indicates pressed (pulled to ground) and 1 indicates not pressed
  230. //
  231. int AIOReadButton(void)
  232. {
  233. if (iBoardType != -1)
  234. {
  235. return AIOReadGPIO(0);
  236. }
  237. return 0;
  238. } /* AIOReadButton() */
  239. //
  240. // Returns the number of pins for the current board
  241. // This can include the 3 pins for the TTY header since the RX/TX lines can also
  242. // be used as ordinary GPIO inputs/outputs
  243. //
  244. int AIOPinCount(void)
  245. {
  246. if (iBoardType != -1)
  247. {
  248. return iPinCount[iBoardType];
  249. }
  250. return 0;
  251. } /* AIOPinCount() */
  252. //
  253. // Simultaneous read/write to SPI bus
  254. //
  255. int AIOReadWriteSPI(int iHandle, unsigned char *pTxBuf, unsigned char *pRxBuf, int iLen)
  256. {
  257. int rc;
  258. xfer.rx_buf = (unsigned long)pRxBuf;
  259. xfer.tx_buf = (unsigned long)pTxBuf;
  260. xfer.len = iLen;
  261. rc = ioctl(iHandle, SPI_IOC_MESSAGE(1), &xfer);
  262. return rc;
  263. } /* AIOReadWriteSPI() */
  264. //
  265. // Read from SPI bus
  266. //
  267. int AIOReadSPI(int iHandle, unsigned char *buf, int iLen)
  268. {
  269. int rc;
  270. xfer.rx_buf = (unsigned long)buf;
  271. xfer.tx_buf = 0;
  272. xfer.len = iLen;
  273. rc = ioctl(iHandle, SPI_IOC_MESSAGE(1), &xfer);
  274. return rc;
  275. } /* AIOReadSPI() */
  276. //
  277. // Write to SPI bus
  278. //
  279. int AIOWriteSPI(int iHandle, unsigned char *pBuf, int iLen)
  280. {
  281. int rc;
  282. xfer.rx_buf = 0;
  283. xfer.tx_buf = (unsigned long)pBuf;
  284. xfer.len = iLen;
  285. rc = ioctl(iHandle, SPI_IOC_MESSAGE(1), &xfer);
  286. return rc;
  287. } /* AIOWriteSPI() */
  288. int AIOOpenI2C(int iChannel, int iAddress)
  289. {
  290. char filename[32];
  291. int file_i2c;
  292. sprintf(filename, "/dev/i2c-%d", iChannel);
  293. if ((file_i2c = open(filename, O_RDWR)) < 0)
  294. {
  295. fprintf(stderr, "Failed to open the i2c bus\n");
  296. return -1;
  297. }
  298. if (ioctl(file_i2c, I2C_SLAVE, iAddress) < 0)
  299. {
  300. fprintf(stderr, "Failed to acquire bus access or talk to slave\n");
  301. return -1;
  302. }
  303. return file_i2c;
  304. } /* AIOOpenI2C() */
  305. void AIOCloseI2C(int iHandle)
  306. {
  307. close(iHandle);
  308. } /* AIOCloseI2C() */
  309. int AIOReadI2C(int iHandle, unsigned char ucRegister, unsigned char *buf, int iCount)
  310. {
  311. int rc;
  312. // Reading from an I2C device involves first writing the 8-bit register
  313. // followed by reading the data
  314. rc = write(iHandle, &ucRegister, 1); // write the register value
  315. if (rc == 1)
  316. {
  317. rc = read(iHandle, buf, iCount);
  318. }
  319. return rc;
  320. } /* AIOReadI2C() */
  321. int AIOWriteI2C(int iHandle, unsigned char ucRegister, unsigned char *buf, int iCount)
  322. {
  323. int rc;
  324. unsigned char ucTemp[2048];
  325. // Writing to an I2C device involves first writing the 8-bit register
  326. // followed by writing the data
  327. ucTemp[0] = ucRegister; // some devices need it written atomically
  328. memcpy(&ucTemp[1], buf, iCount);
  329. rc = write(iHandle, ucTemp, iCount+1);
  330. return rc;
  331. } /* AIOWriteI2C() */
  332. //
  333. // Read from a GPIO pin
  334. //
  335. int AIOReadGPIO(int iPin)
  336. {
  337. int iGPIO = 0;
  338. char szTemp[64];
  339. int rc;
  340. int *pPins;
  341. if (iBoardType == -1) // library not initialized
  342. return -1;
  343. if (iPin < 0 || (iPin != IR_PIN && iPin > iPinCount[iBoardType])) // invalid pin number for this board
  344. return -1;
  345. if (iPin == IR_PIN && iIR_GPIO[iBoardType] == 0) // no IR receiver
  346. return -1;
  347. if (iPinHandles[iPin] == -1)
  348. {
  349. pPins = iPinLists[iBoardType];
  350. if (iPin == IR_PIN)
  351. iGPIO = iIR_GPIO[iBoardType];
  352. else
  353. iGPIO = pPins[iPin];
  354. sprintf(szTemp, "/sys/class/gpio/gpio%d/value", iGPIO);
  355. iPinHandles[iPin] = open(szTemp, O_RDONLY);
  356. }
  357. lseek(iPinHandles[iPin], 0, SEEK_SET); // reset file pointer to start
  358. rc = read(iPinHandles[iPin], szTemp, 1);
  359. if (rc <= 0) // problem
  360. {
  361. fprintf(stderr, "Error reading from GPIO %d\n", iGPIO);
  362. return -1;
  363. }
  364. return (szTemp[0] == '1');
  365. } /* AIOReadGPIO() */
  366. //
  367. // Write a 0 or 1 to a GPIO output line
  368. //
  369. int AIOWriteGPIO(int iPin, int iValue)
  370. {
  371. int rc, iGPIO;
  372. char szTemp[64];
  373. int *pPins;
  374. if (iBoardType == -1) // not initialized
  375. return 0;
  376. if (iPin < 1 || iPin > iPinCount[iBoardType])
  377. return 0;
  378. if (iPinHandles[iPin] == -1) // not open yet
  379. {
  380. pPins = iPinLists[iBoardType];
  381. iGPIO = pPins[iPin]; // convert to GPIO number
  382. sprintf(szTemp, "/sys/class/gpio/gpio%d/value", iGPIO);
  383. iPinHandles[iPin] = open(szTemp, O_WRONLY);
  384. }
  385. if (iValue) rc = write(iPinHandles[iPin], "1", 1);
  386. else rc = write(iPinHandles[iPin], "0", 1);
  387. if (rc < 0) // error
  388. { // do something
  389. }
  390. return 1;
  391. } /* AIOWriteGPIO() */
  392. //
  393. // Set edge value for an open pin
  394. //
  395. int AIOWriteGPIOEdge(int iPin, int iEdge)
  396. {
  397. char szName[64];
  398. int file_gpio, rc, iGPIO;
  399. int *pPins;
  400. char *szEdges[] = {"falling\n","rising\n","both\n","none\n"};
  401. if (iEdge < EDGE_FALLING || iEdge > EDGE_NONE)
  402. return 0;
  403. if (iBoardType == -1) // not initialized
  404. return 0;
  405. if (iPin < 0 || (iPin != IR_PIN && iPin > iPinCount[iBoardType]))
  406. return 0;
  407. pPins = iPinLists[iBoardType];
  408. // Set the mapped pin
  409. if (iPin == IR_PIN)
  410. iGPIO = iIR_GPIO[iBoardType];
  411. else
  412. iGPIO = pPins[iPin];
  413. sprintf(szName, "/sys/class/gpio/gpio%d/edge", iGPIO);
  414. file_gpio = open(szName, O_WRONLY);
  415. // Write edge type
  416. rc = write(file_gpio, szEdges[iEdge], strlen(szEdges[iEdge]));
  417. close(file_gpio);
  418. if (rc < 0) // error
  419. { // do something
  420. }
  421. return 1;
  422. } /* AIOWriteGPIOEdge() */
  423. //
  424. // GPIO Monitoring thread (one for each pin)
  425. //
  426. void *GPIOThread(void *param)
  427. {
  428. int iPin = (int)param; // pin number is passed in
  429. struct pollfd fdset[1];
  430. char szName[32], szTemp[64];
  431. int gpio_fd;
  432. int *pPins, rc, iGPIO;
  433. int timeout = 3000; // 3 seconds
  434. pPins = iPinLists[iBoardType];
  435. if (iPin == IR_PIN)
  436. iGPIO = iIR_GPIO[iBoardType];
  437. else
  438. iGPIO = pPins[iPin];
  439. sprintf(szName, "/sys/class/gpio/gpio%d/value", iGPIO);
  440. gpio_fd = open(szName, O_RDONLY);
  441. if (gpio_fd < 0) // something went wrong
  442. return NULL;
  443. lseek(gpio_fd, 0, SEEK_SET);
  444. rc = read(gpio_fd, szTemp, 64); // initial read to prevent false interrupt
  445. while (1)
  446. {
  447. // If the callback is NULL then exit thread
  448. if (cbList[iPin] == NULL)
  449. return NULL;
  450. memset(fdset, 0, sizeof(fdset));
  451. fdset[0].fd = gpio_fd;
  452. fdset[0].events = POLLPRI;
  453. rc = poll(&fdset[0], 1, timeout);
  454. if (rc < 0) return NULL;
  455. // clear the interrupt by reading the data
  456. lseek(gpio_fd, 0, SEEK_SET);
  457. rc = read(gpio_fd, szTemp, 64);
  458. // see if it was a valid interrupt event
  459. if (fdset[0].revents & POLLPRI)
  460. {
  461. if (cbList[iPin])
  462. (*cbList[iPin])(iPin);
  463. }
  464. }
  465. return NULL;
  466. } /* GPIOThread() */
  467. //
  468. // Set edge to call the given function when the state
  469. // changes. AIOAddGPIO must be called first with direction
  470. // set to GPIO_IN
  471. //
  472. int AIOAddGPIOCallback(int iPin, AIOCALLBACK callback)
  473. {
  474. int *pPins;
  475. pthread_t tinfo;
  476. if (iBoardType == -1) // not initialize
  477. return 0;
  478. pPins = iPinLists[iBoardType];
  479. if (iPin != IR_PIN && pPins[iPin] == -1) // invalid pin
  480. return 0;
  481. cbList[iPin] = callback; // save the callback pointer
  482. // Start a thread to manage the interrupt/callback
  483. pthread_create(&tinfo, NULL, GPIOThread, (void *)iPin);
  484. return 1;
  485. } /* AIOAddGPIOCallback() */
  486. //
  487. // Set pointer in callback list to NULL to cause
  488. // thread to exit
  489. //
  490. int AIORemoveGPIOCallback(int iPin)
  491. {
  492. if (iBoardType == -1) // not initialize
  493. return 0;
  494. if (cbList[iPin] == NULL) // invalid pin
  495. return 0;
  496. cbList[iPin] = NULL; // This will force thread to exit
  497. return 1;
  498. } /* AIORemoveGPIOCallback() */
  499. long getTimeInMicroseconds()
  500. {
  501. struct timespec time_p;
  502. clock_gettime(CLOCK_MONOTONIC, &time_p);
  503. return (time_p.tv_sec % 10) * 1000000 + time_p.tv_nsec / 1000;
  504. }
  505. //
  506. // GPIO Monitoring thread for IR (one for each pin)
  507. // Code length must be less than 50.
  508. //
  509. void *GPIOIRThread(void *param)
  510. {
  511. int iPin = (int)param; // pin number is passed in
  512. int endOfCodeTimeOut = 3; // after 3 ms we think code has ended.
  513. struct pollfd fdset[1];
  514. char szName[32], szTemp[64];
  515. int gpio_fd;
  516. int *pPins, rc, iGPIO;
  517. int timeout = 3000; // 3 seconds
  518. long start = getTimeInMicroseconds();
  519. int currentCode[52];
  520. int i, codePointer = 0;
  521. pPins = iPinLists[iBoardType];
  522. if (iPin == IR_PIN)
  523. iGPIO = iIR_GPIO[iBoardType];
  524. else
  525. iGPIO = pPins[iPin];
  526. sprintf(szName, "/sys/class/gpio/gpio%d/value", iGPIO);
  527. gpio_fd = open(szName, O_RDONLY);
  528. if (gpio_fd < 0) // something went wrong
  529. return NULL;
  530. lseek(gpio_fd, 0, SEEK_SET);
  531. rc = read(gpio_fd, szTemp, 64); // initial read to prevent false interrupt
  532. while (1)
  533. {
  534. // If the callback is NULL then exit thread
  535. if (cbIRList[iPin] == NULL)
  536. return NULL;
  537. memset(fdset, 0, sizeof(fdset));
  538. fdset[0].fd = gpio_fd;
  539. fdset[0].events = POLLPRI;
  540. rc = poll(&fdset[0], 1, timeout);
  541. if (rc < 0) return NULL;
  542. // clear the interrupt by reading the data
  543. lseek(gpio_fd, 0, SEEK_SET);
  544. rc = read(gpio_fd, szTemp, 64);
  545. // see if it was a valid interrupt event
  546. if (fdset[0].revents & POLLPRI)
  547. {
  548. long now = getTimeInMicroseconds();
  549. long between = now - start;
  550. // printf("between: %11d\n", between);
  551. currentCode[codePointer] = (int) between;
  552. codePointer++;
  553. timeout = endOfCodeTimeOut;
  554. start = now;
  555. // printf("cp: %d", codePointer);
  556. if(codePointer > 50) { // max code length reached, send what we have.
  557. if (cbIRList[iPin])
  558. (*cbIRList[iPin])(currentCode);
  559. codePointer = 0;
  560. for(i = 0; i < 50; i++) { currentCode[i] = 0; }
  561. }
  562. } else if(timeout == endOfCodeTimeOut) { // are we receiving a code currently?
  563. //printf("Between: %d\n", getTimeInMicroseconds() - start);
  564. if (cbIRList[iPin])
  565. (*cbIRList[iPin])(currentCode);
  566. timeout = 3000; // wait for next code again, with the default timeout
  567. codePointer = 0;
  568. for(i = 0; i < 50; i++) { currentCode[i] = 0; }
  569. } else {
  570. printf("Code timeout\n");
  571. }
  572. }
  573. return NULL;
  574. } /* GPIOIRThread() */
  575. int AIOAddGPIOIRCallback(int iPin, AIOIRCALLBACK callback)
  576. {
  577. int *pPins;
  578. pthread_t tinfo;
  579. if (iBoardType == -1) // not initialize
  580. return 0;
  581. pPins = iPinLists[iBoardType];
  582. if (iPin != IR_PIN && pPins[iPin] == -1) // invalid pin
  583. return 0;
  584. cbIRList[iPin] = callback; // save the callback pointer
  585. // Start a thread to manage the interrupt/callback
  586. pthread_create(&tinfo, NULL, GPIOIRThread, (void *)iPin);
  587. return 1;
  588. } /* AIOAddGPIOCallback() */
  589. int AIORemoveGPIOIRCallback(int iPin)
  590. {
  591. if (iBoardType == -1) // not initialize
  592. return 0;
  593. if (cbIRList[iPin] == NULL) // invalid pin
  594. return 0;
  595. cbIRList[iPin] = NULL; // This will force thread to exit
  596. return 1;
  597. } /* AIORemoveGPIOIRCallback() */
  598. //
  599. // Initialize a GPIO line for input or output
  600. // This will export it to the sysfs driver and
  601. // it will appear in /sys/class/gpio
  602. //
  603. int AIOAddGPIO(int iPin, int iDirection)
  604. {
  605. char szName[64];
  606. int file_gpio, rc, iGPIO;
  607. int *pPins;
  608. if (iBoardType == -1) // not initialize
  609. return 0;
  610. pPins = iPinLists[iBoardType];
  611. if (iPin != IR_PIN && pPins[iPin] == -1) // invalid pin
  612. return 0;
  613. if (iPin == IR_PIN && iIR_GPIO[iBoardType] == 0)
  614. return 0; // invalid IR pin
  615. file_gpio = open("/sys/class/gpio/export", O_WRONLY);
  616. if (iPin == IR_PIN)
  617. iGPIO = iIR_GPIO[iBoardType];
  618. else
  619. iGPIO = pPins[iPin];
  620. sprintf(szName, "%d", iGPIO);
  621. rc = write(file_gpio, szName, strlen(szName));
  622. close(file_gpio);
  623. sprintf(szName, "/sys/class/gpio/gpio%d/direction", iGPIO);
  624. file_gpio = open(szName, O_WRONLY);
  625. if (iDirection == GPIO_OUT)
  626. rc = write(file_gpio, "out\n", 4);
  627. else
  628. rc = write(file_gpio, "in\n", 3);
  629. close(file_gpio);
  630. if (iDirection == GPIO_IN_PULLUP) // RPI specific feature, use GPIO library
  631. {
  632. sprintf(szName, "gpio mode %d up", iWiringPiPins[iPin]);
  633. system(szName);
  634. }
  635. if (rc < 0) // added to suppress compiler warnings
  636. { // do nothing
  637. }
  638. return 1;
  639. } /* AIOAddGPIO() */
  640. //
  641. // Remove access to a GPIO pin
  642. // This will 'unexport' it from the sysfs driver
  643. // and remove it from the /sys/class/gpio directory
  644. //
  645. void AIORemoveGPIO(int iPin)
  646. {
  647. int file_gpio, rc;
  648. char szTemp[64];
  649. int *pPins;
  650. if (iBoardType == -1) // not initialized
  651. return;
  652. if (iPin < 1 || iPin > MAX_PINS) // invalid pin
  653. return;
  654. if (iPinHandles[iPin] != -1)
  655. {
  656. close(iPinHandles[iPin]);
  657. file_gpio = open("/sys/class/gpio/unexport", O_WRONLY);
  658. pPins = iPinLists[iBoardType];
  659. sprintf(szTemp, "%d", pPins[iPin]);
  660. rc = write(file_gpio, szTemp, strlen(szTemp));
  661. close(file_gpio);
  662. if (rc < 0) // suppress compiler warning
  663. { // do nothing
  664. }
  665. iPinHandles[iPin] = -1;
  666. }
  667. } /* AIORemoveGPIO() */
  668. //
  669. // Open a handle to the SPI bus
  670. //
  671. int AIOOpenSPI(int iChannel, int iSPIFreq)
  672. {
  673. int rc, iSPIMode = SPI_MODE_0; // | SPI_NO_CS;
  674. char szName[32];
  675. int file_spi;
  676. int i = iSPIFreq;
  677. sprintf(szName,"/dev/spidev%d.0", iChannel);
  678. file_spi = open(szName, O_RDWR);
  679. rc = ioctl(file_spi, SPI_IOC_WR_MODE, &iSPIMode);
  680. if (rc < 0) fprintf(stderr, "Error setting SPI mode\n");
  681. rc = ioctl(file_spi, SPI_IOC_WR_MAX_SPEED_HZ, &i);
  682. if (rc < 0) fprintf(stderr, "Error setting SPI speed\n");
  683. memset(&xfer, 0, sizeof(xfer));
  684. xfer.speed_hz = iSPIFreq;
  685. xfer.cs_change = 0;
  686. xfer.delay_usecs = 0;
  687. xfer.bits_per_word = 8;
  688. if (file_spi < 0)
  689. {
  690. fprintf(stderr, "Failed to open the SPI bus\n");
  691. return -1;
  692. }
  693. return file_spi;
  694. } /* AIOOpenSPI() */
  695. void AIOCloseSPI(int iHandle)
  696. {
  697. close(iHandle);
  698. } /* AIOCloseSPI() */
  699. //
  700. // Returns the name of the board (if recognized)
  701. //
  702. const char * AIOGetBoardName(void)
  703. {
  704. if (iBoardType == -1)
  705. return "Unknown";
  706. else
  707. return szBoardNames[iBoardType];
  708. } /* AIOGetBoardName() */