Smart-Home am Beispiel der Präsenzerkennung im Raum Projektarbeit Lennart Heimbs, Johannes Krug, Sebastian Dohle und Kevin Holzschuh bei Prof. Oliver Hofmann SS2019
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.

SPIDEV.cpp 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /*
  2. * The MySensors Arduino library handles the wireless radio link and protocol
  3. * between your home built sensors/actuators and HA controller of choice.
  4. * The sensors forms a self healing radio network with optional repeaters. Each
  5. * repeater and gateway builds a routing tables in EEPROM which keeps track of the
  6. * network topology allowing messages to be routed to nodes.
  7. *
  8. * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
  9. * Copyright (C) 2013-2018 Sensnology AB
  10. * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
  11. *
  12. * Documentation: http://www.mysensors.org
  13. * Support Forum: http://forum.mysensors.org
  14. *
  15. * This program is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU General Public License
  17. * version 2 as published by the Free Software Foundation.
  18. *
  19. * Based on TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard <tmrh20@gmail.com>
  20. */
  21. #include "SPIDEV.h"
  22. #include <fcntl.h>
  23. #include <pthread.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <sys/ioctl.h>
  27. #include <unistd.h>
  28. #include "log.h"
  29. static pthread_mutex_t spiMutex = PTHREAD_MUTEX_INITIALIZER;
  30. static pthread_mutexattr_t attr;
  31. // Declare a single default instance
  32. SPIDEVClass SPIDEV = SPIDEVClass();
  33. uint8_t SPIDEVClass::initialized = 0;
  34. int SPIDEVClass::fd = -1;
  35. std::string SPIDEVClass::device = SPI_SPIDEV_DEVICE;
  36. uint8_t SPIDEVClass::mode = SPI_MODE0;
  37. uint32_t SPIDEVClass::speed = SPI_CLOCK_BASE;
  38. uint8_t SPIDEVClass::bit_order = MSBFIRST;
  39. struct spi_ioc_transfer SPIDEVClass::tr = {0,0,0,0,0,8,0,0,0,0}; // 8 bits_per_word, 0 cs_change
  40. SPIDEVClass::SPIDEVClass()
  41. {
  42. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
  43. pthread_mutex_init(&spiMutex, &attr);
  44. }
  45. void SPIDEVClass::begin(int busNo)
  46. {
  47. if (!initialized) {
  48. /* set spidev accordingly to busNo like:
  49. * busNo = 23 -> /dev/spidev2.3
  50. *
  51. * a bit messy but simple
  52. * */
  53. device[11] += (busNo / 10) % 10;
  54. device[13] += busNo % 10;
  55. init();
  56. }
  57. initialized++; // reference count
  58. }
  59. void SPIDEVClass::end()
  60. {
  61. if (initialized) {
  62. initialized--;
  63. }
  64. if (!initialized) {
  65. if (!(fd < 0)) {
  66. close(fd);
  67. fd = -1;
  68. }
  69. }
  70. }
  71. void SPIDEVClass::setBitOrder(uint8_t border)
  72. {
  73. pthread_mutex_lock(&spiMutex);
  74. /*
  75. * bit order
  76. */
  77. bit_order = border;
  78. int ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &bit_order);
  79. if (ret == -1) {
  80. logError("Can't set SPI bit order.\n");
  81. abort();
  82. }
  83. ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &bit_order);
  84. if (ret == -1) {
  85. logError("Can't set SPI bit order.\n");
  86. abort();
  87. }
  88. pthread_mutex_unlock(&spiMutex);
  89. }
  90. void SPIDEVClass::setDataMode(uint8_t data_mode)
  91. {
  92. pthread_mutex_lock(&spiMutex);
  93. /*
  94. * spi mode
  95. */
  96. mode = data_mode;
  97. int ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
  98. if (ret == -1) {
  99. logError("Can't set SPI mode.\n");
  100. abort();
  101. }
  102. ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
  103. if (ret == -1) {
  104. logError("Can't set SPI mode.\n");
  105. abort();
  106. }
  107. pthread_mutex_unlock(&spiMutex);
  108. }
  109. void SPIDEVClass::setClockDivider(uint16_t divider)
  110. {
  111. if (divider == 0) {
  112. return;
  113. }
  114. pthread_mutex_lock(&spiMutex);
  115. /*
  116. * max speed hz
  117. */
  118. speed = SPI_CLOCK_BASE / divider;
  119. int ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
  120. if (ret == -1) {
  121. logError("Can't set SPI max speed hz.\n");
  122. abort();
  123. }
  124. ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
  125. if (ret == -1) {
  126. logError("Can't set SPI max speed hz.\n");
  127. abort();
  128. }
  129. pthread_mutex_unlock(&spiMutex);
  130. }
  131. void SPIDEVClass::chipSelect(int csn_chip)
  132. {
  133. if (csn_chip >= 0 && csn_chip <= 9) {
  134. device[13] = '0' + (csn_chip % 10);
  135. init();
  136. }
  137. }
  138. uint8_t SPIDEVClass::transfer(uint8_t data)
  139. {
  140. int ret;
  141. uint8_t tx[1] = {data};
  142. uint8_t rx[1] = {0};
  143. pthread_mutex_lock(&spiMutex);
  144. tr.tx_buf = (unsigned long)&tx[0];
  145. tr.rx_buf = (unsigned long)&rx[0];
  146. tr.len = 1;
  147. tr.speed_hz = speed;
  148. ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
  149. if (ret < 1) {
  150. logError("Can't send spi message.\n");
  151. abort();
  152. }
  153. pthread_mutex_unlock(&spiMutex);
  154. return rx[0];
  155. }
  156. void SPIDEVClass::transfernb(char* tbuf, char* rbuf, uint32_t len)
  157. {
  158. int ret;
  159. pthread_mutex_lock(&spiMutex);
  160. tr.tx_buf = (unsigned long)tbuf;
  161. tr.rx_buf = (unsigned long)rbuf;
  162. tr.len = len;
  163. tr.speed_hz = speed;
  164. ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
  165. if (ret < 1) {
  166. logError("Can't send spi message.\n");
  167. abort();
  168. }
  169. pthread_mutex_unlock(&spiMutex);
  170. }
  171. void SPIDEVClass::transfern(char* buf, uint32_t len)
  172. {
  173. transfernb(buf, buf, len);
  174. }
  175. void SPIDEVClass::beginTransaction(SPISettings settings)
  176. {
  177. int ret;
  178. pthread_mutex_lock(&spiMutex);
  179. /*
  180. * spi mode
  181. */
  182. if (settings.dmode != mode) {
  183. mode = settings.dmode;
  184. ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
  185. if (ret == -1) {
  186. logError("Can't set spi mode.\n");
  187. abort();
  188. }
  189. ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
  190. if (ret == -1) {
  191. logError("Can't set spi mode.\n");
  192. abort();
  193. }
  194. }
  195. /*
  196. * speed
  197. */
  198. if (settings.clock != speed) {
  199. speed = settings.clock;
  200. ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
  201. if (ret == -1) {
  202. logError("Can't set SPI max speed hz.\n");
  203. abort();
  204. }
  205. ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
  206. if (ret == -1) {
  207. logError("Can't set SPI max speed hz.\n");
  208. abort();
  209. }
  210. }
  211. /*
  212. * bit order
  213. */
  214. if (settings.border != bit_order) {
  215. bit_order = settings.border;
  216. ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &bit_order);
  217. if (ret == -1) {
  218. logError("Can't set SPI bit order.\n");
  219. abort();
  220. }
  221. ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &bit_order);
  222. if (ret == -1) {
  223. logError("Can't set SPI bit order.\n");
  224. abort();
  225. }
  226. }
  227. }
  228. void SPIDEVClass::endTransaction()
  229. {
  230. pthread_mutex_unlock(&spiMutex);
  231. }
  232. void SPIDEVClass::usingInterrupt(uint8_t interruptNumber)
  233. {
  234. (void)interruptNumber;
  235. }
  236. void SPIDEVClass::notUsingInterrupt(uint8_t interruptNumber)
  237. {
  238. (void)interruptNumber;
  239. }
  240. void SPIDEVClass::init()
  241. {
  242. pthread_mutex_lock(&spiMutex);
  243. if (fd >= 0) {
  244. close(fd);
  245. }
  246. fd = open(device.c_str(), O_RDWR);
  247. if (fd < 0) {
  248. logError("Can't open SPI device: %s\n", device.c_str());
  249. abort();
  250. }
  251. /*
  252. * spi mode
  253. */
  254. int ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
  255. if (ret == -1) {
  256. logError("Can't set SPI mode.\n");
  257. abort();
  258. }
  259. ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
  260. if (ret == -1) {
  261. logError("Can't set SPI mode.\n");
  262. abort();
  263. }
  264. /*
  265. * bits per word
  266. */
  267. uint8_t bits = 8; // 8 bits per word
  268. ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
  269. if (ret == -1) {
  270. logError("Can't set SPI bits per word.\n");
  271. abort();
  272. }
  273. ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
  274. if (ret == -1) {
  275. logError("Can't set SPI bits per word.\n");
  276. abort();
  277. }
  278. /*
  279. * max speed hz
  280. */
  281. ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
  282. if (ret == -1) {
  283. logError("Can't set SPI max speed hz.\n");
  284. abort();
  285. }
  286. ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
  287. if (ret == -1) {
  288. logError("Can't set SPI max speed hz.\n");
  289. abort();
  290. }
  291. /*
  292. * bit order
  293. */
  294. ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &bit_order);
  295. if (ret == -1) {
  296. logError("Can't set SPI bit order.\n");
  297. abort();
  298. }
  299. ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &bit_order);
  300. if (ret == -1) {
  301. logError("Can't set SPI bit order.\n");
  302. abort();
  303. }
  304. pthread_mutex_unlock(&spiMutex);
  305. }