loragw_spi.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /*
  2. / _____) _ | |
  3. ( (____ _____ ____ _| |_ _____ ____| |__
  4. \____ \| ___ | (_ _) ___ |/ ___) _ \
  5. _____) ) ____| | | || |_| ____( (___| | | |
  6. (______/|_____)_|_|_| \__)_____)\____)_| |_|
  7. (C)2019 Semtech
  8. Description:
  9. Host specific functions to address the LoRa concentrator registers through
  10. a SPI interface.
  11. Single-byte read/write and burst read/write.
  12. Could be used with multiple SPI ports in parallel (explicit file descriptor)
  13. License: Revised BSD License, see LICENSE.TXT file include in the project
  14. */
  15. /* -------------------------------------------------------------------------- */
  16. /* --- DEPENDANCIES --------------------------------------------------------- */
  17. #include <stdint.h> /* C99 types */
  18. #include <stdio.h> /* printf fprintf */
  19. #include <stdlib.h> /* malloc free */
  20. #include <unistd.h> /* lseek, close */
  21. #include <fcntl.h> /* open */
  22. #include <string.h> /* memset */
  23. #include <sys/ioctl.h>
  24. #include <linux/spi/spidev.h>
  25. #include "loragw_spi.h"
  26. #include "loragw_aux.h"
  27. /* -------------------------------------------------------------------------- */
  28. /* --- PRIVATE MACROS ------------------------------------------------------- */
  29. #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
  30. #if DEBUG_COM == 1
  31. #define DEBUG_MSG(str) fprintf(stdout, str)
  32. #define DEBUG_PRINTF(fmt, args...) fprintf(stdout,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
  33. #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_SPI_ERROR;}
  34. #else
  35. #define DEBUG_MSG(str)
  36. #define DEBUG_PRINTF(fmt, args...)
  37. #define CHECK_NULL(a) if(a==NULL){return LGW_SPI_ERROR;}
  38. #endif
  39. /* -------------------------------------------------------------------------- */
  40. /* --- PRIVATE CONSTANTS ---------------------------------------------------- */
  41. #define READ_ACCESS 0x00
  42. #define WRITE_ACCESS 0x80
  43. #define LGW_BURST_CHUNK 1024
  44. /* -------------------------------------------------------------------------- */
  45. /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
  46. /* SPI initialization and configuration */
  47. int lgw_spi_open(const char * com_path, void **com_target_ptr) {
  48. int *spi_device = NULL;
  49. int dev;
  50. int a=0, b=0;
  51. int i;
  52. /* check input variables */
  53. CHECK_NULL(com_path);
  54. CHECK_NULL(com_target_ptr);
  55. /* allocate memory for the device descriptor */
  56. spi_device = malloc(sizeof(int));
  57. if (spi_device == NULL) {
  58. DEBUG_MSG("ERROR: MALLOC FAIL\n");
  59. return LGW_SPI_ERROR;
  60. }
  61. /* open SPI device */
  62. dev = open(com_path, O_RDWR);
  63. if (dev < 0) {
  64. DEBUG_PRINTF("ERROR: failed to open SPI device %s\n", com_path);
  65. return LGW_SPI_ERROR;
  66. }
  67. /* setting SPI mode to 'mode 0' */
  68. i = SPI_MODE_0;
  69. a = ioctl(dev, SPI_IOC_WR_MODE, &i);
  70. b = ioctl(dev, SPI_IOC_RD_MODE, &i);
  71. if ((a < 0) || (b < 0)) {
  72. DEBUG_MSG("ERROR: SPI PORT FAIL TO SET IN MODE 0\n");
  73. close(dev);
  74. free(spi_device);
  75. return LGW_SPI_ERROR;
  76. }
  77. /* setting SPI max clk (in Hz) */
  78. i = SPI_SPEED;
  79. a = ioctl(dev, SPI_IOC_WR_MAX_SPEED_HZ, &i);
  80. b = ioctl(dev, SPI_IOC_RD_MAX_SPEED_HZ, &i);
  81. if ((a < 0) || (b < 0)) {
  82. DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MAX SPEED\n");
  83. close(dev);
  84. free(spi_device);
  85. return LGW_SPI_ERROR;
  86. }
  87. /* setting SPI to MSB first */
  88. i = 0;
  89. a = ioctl(dev, SPI_IOC_WR_LSB_FIRST, &i);
  90. b = ioctl(dev, SPI_IOC_RD_LSB_FIRST, &i);
  91. if ((a < 0) || (b < 0)) {
  92. DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MSB FIRST\n");
  93. close(dev);
  94. free(spi_device);
  95. return LGW_SPI_ERROR;
  96. }
  97. /* setting SPI to 8 bits per word */
  98. i = 0;
  99. a = ioctl(dev, SPI_IOC_WR_BITS_PER_WORD, &i);
  100. b = ioctl(dev, SPI_IOC_RD_BITS_PER_WORD, &i);
  101. if ((a < 0) || (b < 0)) {
  102. DEBUG_MSG("ERROR: SPI PORT FAIL TO SET 8 BITS-PER-WORD\n");
  103. close(dev);
  104. return LGW_SPI_ERROR;
  105. }
  106. *spi_device = dev;
  107. *com_target_ptr = (void *)spi_device;
  108. DEBUG_MSG("Note: SPI port opened and configured ok\n");
  109. return LGW_SPI_SUCCESS;
  110. }
  111. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  112. /* SPI release */
  113. int lgw_spi_close(void *com_target) {
  114. int spi_device;
  115. int a;
  116. /* check input variables */
  117. CHECK_NULL(com_target);
  118. /* close file & deallocate file descriptor */
  119. spi_device = *(int *)com_target; /* must check that spi_target is not null beforehand */
  120. a = close(spi_device);
  121. free(com_target);
  122. /* determine return code */
  123. if (a < 0) {
  124. DEBUG_MSG("ERROR: SPI PORT FAILED TO CLOSE\n");
  125. return LGW_SPI_ERROR;
  126. } else {
  127. DEBUG_MSG("Note: SPI port closed\n");
  128. return LGW_SPI_SUCCESS;
  129. }
  130. }
  131. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  132. /* Simple write */
  133. int lgw_spi_w(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t data) {
  134. int spi_device;
  135. uint8_t out_buf[4];
  136. uint8_t command_size;
  137. struct spi_ioc_transfer k;
  138. int a;
  139. /* check input variables */
  140. CHECK_NULL(com_target);
  141. spi_device = *(int *)com_target; /* must check that spi_target is not null beforehand */
  142. /* prepare frame to be sent */
  143. out_buf[0] = spi_mux_target;
  144. out_buf[1] = WRITE_ACCESS | ((address >> 8) & 0x7F);
  145. out_buf[2] = ((address >> 0) & 0xFF);
  146. out_buf[3] = data;
  147. command_size = 4;
  148. /* I/O transaction */
  149. memset(&k, 0, sizeof(k)); /* clear k */
  150. k.tx_buf = (unsigned long) out_buf;
  151. k.len = command_size;
  152. k.speed_hz = SPI_SPEED;
  153. k.cs_change = 0;
  154. k.bits_per_word = 8;
  155. a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
  156. /* determine return code */
  157. if (a != (int)k.len) {
  158. DEBUG_MSG("ERROR: SPI WRITE FAILURE\n");
  159. return LGW_SPI_ERROR;
  160. } else {
  161. DEBUG_MSG("Note: SPI write success\n");
  162. return LGW_SPI_SUCCESS;
  163. }
  164. }
  165. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  166. /* Simple read */
  167. int lgw_spi_r(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t *data) {
  168. int spi_device;
  169. uint8_t out_buf[5];
  170. uint8_t command_size;
  171. uint8_t in_buf[ARRAY_SIZE(out_buf)];
  172. struct spi_ioc_transfer k;
  173. int a;
  174. /* check input variables */
  175. CHECK_NULL(com_target);
  176. CHECK_NULL(data);
  177. spi_device = *(int *)com_target; /* must check that com_target is not null beforehand */
  178. /* prepare frame to be sent */
  179. out_buf[0] = spi_mux_target;
  180. out_buf[1] = READ_ACCESS | ((address >> 8) & 0x7F);
  181. out_buf[2] = ((address >> 0) & 0xFF);
  182. out_buf[3] = 0x00;
  183. out_buf[4] = 0x00;
  184. command_size = 5;
  185. /* I/O transaction */
  186. memset(&k, 0, sizeof(k)); /* clear k */
  187. k.tx_buf = (unsigned long) out_buf;
  188. k.rx_buf = (unsigned long) in_buf;
  189. k.len = command_size;
  190. k.cs_change = 0;
  191. a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
  192. /* determine return code */
  193. if (a != (int)k.len) {
  194. DEBUG_MSG("ERROR: SPI READ FAILURE\n");
  195. return LGW_SPI_ERROR;
  196. } else {
  197. DEBUG_MSG("Note: SPI read success\n");
  198. *data = in_buf[command_size - 1];
  199. return LGW_SPI_SUCCESS;
  200. }
  201. }
  202. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  203. /* Single Byte Read-Modify-Write */
  204. int lgw_spi_rmw(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t offs, uint8_t leng, uint8_t data) {
  205. int spi_stat = LGW_SPI_SUCCESS;
  206. uint8_t buf[4] = "\x00\x00\x00\x00";
  207. /* Read */
  208. spi_stat += lgw_spi_r(com_target, spi_mux_target, address, &buf[0]);
  209. /* Modify */
  210. buf[1] = ((1 << leng) - 1) << offs; /* bit mask */
  211. buf[2] = ((uint8_t)data) << offs; /* new data offsetted */
  212. buf[3] = (~buf[1] & buf[0]) | (buf[1] & buf[2]); /* mixing old & new data */
  213. /* Write */
  214. spi_stat += lgw_spi_w(com_target, spi_mux_target, address, buf[3]);
  215. return spi_stat;
  216. }
  217. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  218. /* Burst (multiple-byte) write */
  219. int lgw_spi_wb(void *com_target, uint8_t spi_mux_target, uint16_t address, const uint8_t *data, uint16_t size) {
  220. int spi_device;
  221. uint8_t command[3];
  222. uint8_t command_size;
  223. struct spi_ioc_transfer k[2];
  224. int size_to_do, chunk_size, offset;
  225. int byte_transfered = 0;
  226. int i;
  227. /* check input parameters */
  228. CHECK_NULL(com_target);
  229. CHECK_NULL(data);
  230. if (size == 0) {
  231. DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n");
  232. return LGW_SPI_ERROR;
  233. }
  234. spi_device = *(int *)com_target; /* must check that com_target is not null beforehand */
  235. /* prepare command byte */
  236. command[0] = spi_mux_target;
  237. command[1] = WRITE_ACCESS | ((address >> 8) & 0x7F);
  238. command[2] = ((address >> 0) & 0xFF);
  239. command_size = 3;
  240. size_to_do = size;
  241. /* I/O transaction */
  242. memset(&k, 0, sizeof(k)); /* clear k */
  243. k[0].tx_buf = (unsigned long) &command[0];
  244. k[0].len = command_size;
  245. k[0].cs_change = 0;
  246. k[1].cs_change = 0;
  247. for (i=0; size_to_do > 0; ++i) {
  248. chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK;
  249. offset = i * LGW_BURST_CHUNK;
  250. k[1].tx_buf = (unsigned long)(data + offset);
  251. k[1].len = chunk_size;
  252. byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - k[0].len );
  253. DEBUG_PRINTF("BURST WRITE: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered);
  254. size_to_do -= chunk_size; /* subtract the quantity of data already transferred */
  255. }
  256. /* determine return code */
  257. if (byte_transfered != size) {
  258. DEBUG_MSG("ERROR: SPI BURST WRITE FAILURE\n");
  259. return LGW_SPI_ERROR;
  260. } else {
  261. DEBUG_MSG("Note: SPI burst write success\n");
  262. return LGW_SPI_SUCCESS;
  263. }
  264. }
  265. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  266. /* Burst (multiple-byte) read */
  267. int lgw_spi_rb(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t *data, uint16_t size) {
  268. int spi_device;
  269. uint8_t command[4];
  270. uint8_t command_size;
  271. struct spi_ioc_transfer k[2];
  272. int size_to_do, chunk_size, offset;
  273. int byte_transfered = 0;
  274. int i;
  275. /* check input parameters */
  276. CHECK_NULL(com_target);
  277. CHECK_NULL(data);
  278. if (size == 0) {
  279. DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n");
  280. return LGW_SPI_ERROR;
  281. }
  282. spi_device = *(int *)com_target; /* must check that com_target is not null beforehand */
  283. /* prepare command byte */
  284. command[0] = spi_mux_target;
  285. command[1] = READ_ACCESS | ((address >> 8) & 0x7F);
  286. command[2] = ((address >> 0) & 0xFF);
  287. command[3] = 0x00;
  288. command_size = 4;
  289. size_to_do = size;
  290. /* I/O transaction */
  291. memset(&k, 0, sizeof(k)); /* clear k */
  292. k[0].tx_buf = (unsigned long) &command[0];
  293. k[0].len = command_size;
  294. k[0].cs_change = 0;
  295. k[1].cs_change = 0;
  296. for (i=0; size_to_do > 0; ++i) {
  297. chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK;
  298. offset = i * LGW_BURST_CHUNK;
  299. k[1].rx_buf = (unsigned long)(data + offset);
  300. k[1].len = chunk_size;
  301. byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - k[0].len );
  302. DEBUG_PRINTF("BURST READ: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered);
  303. size_to_do -= chunk_size; /* subtract the quantity of data already transferred */
  304. }
  305. /* determine return code */
  306. if (byte_transfered != size) {
  307. DEBUG_MSG("ERROR: SPI BURST READ FAILURE\n");
  308. return LGW_SPI_ERROR;
  309. } else {
  310. DEBUG_MSG("Note: SPI burst read success\n");
  311. return LGW_SPI_SUCCESS;
  312. }
  313. }
  314. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  315. uint16_t lgw_spi_chunk_size(void) {
  316. return (uint16_t)LGW_BURST_CHUNK;
  317. }
  318. /* --- EOF ------------------------------------------------------------------ */