loragw_sx1261.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. /*
  2. / _____) _ | |
  3. ( (____ _____ ____ _| |_ _____ ____| |__
  4. \____ \| ___ | (_ _) ___ |/ ___) _ \
  5. _____) ) ____| | | || |_| ____( (___| | | |
  6. (______/|_____)_|_|_| \__)_____)\____)_| |_|
  7. (C)2019 Semtech
  8. Description:
  9. Functions used to handle LoRa concentrator SX1261 radio used to handle LBT
  10. and Spectral Scan.
  11. License: Revised BSD License, see LICENSE.TXT file include in the project
  12. */
  13. /* -------------------------------------------------------------------------- */
  14. /* --- DEPENDANCIES --------------------------------------------------------- */
  15. #include <stdint.h> /* C99 types */
  16. #include <stdio.h> /* printf fprintf */
  17. #include <string.h> /* strncmp */
  18. #include "loragw_sx1261.h"
  19. #include "loragw_spi.h"
  20. #include "loragw_com.h"
  21. #include "loragw_aux.h"
  22. #include "loragw_reg.h"
  23. #include "loragw_hal.h"
  24. #include "sx1261_com.h"
  25. #include "sx1261_pram.var"
  26. /* -------------------------------------------------------------------------- */
  27. /* --- PRIVATE MACROS ------------------------------------------------------- */
  28. #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
  29. #if DEBUG_LBT == 1
  30. #define DEBUG_MSG(str) fprintf(stdout, str)
  31. #define DEBUG_PRINTF(fmt, args...) fprintf(stdout,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
  32. #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;}
  33. #else
  34. #define DEBUG_MSG(str)
  35. #define DEBUG_PRINTF(fmt, args...)
  36. #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;}
  37. #endif
  38. #define CHECK_ERR(a) if(a==-1){return LGW_REG_ERROR;}
  39. #define DEBUG_SX1261_GET_STATUS 0
  40. /* -------------------------------------------------------------------------- */
  41. /* --- PRIVATE CONSTANTS ---------------------------------------------------- */
  42. #define SX1261_PRAM_VERSION_FULL_SIZE 16 /* 15 bytes + terminating char */
  43. /* -------------------------------------------------------------------------- */
  44. /* --- PRIVATE VARIABLES ---------------------------------------------------- */
  45. /* -------------------------------------------------------------------------- */
  46. /* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
  47. int sx1261_pram_get_version(char * version_str) {
  48. uint8_t buff[3 + SX1261_PRAM_VERSION_FULL_SIZE] = { 0 };
  49. int x;
  50. /* Check input parameter */
  51. CHECK_NULL(version_str);
  52. /* Get version string (15 bytes) at address 0x320 */
  53. buff[0] = 0x03;
  54. buff[1] = 0x20;
  55. buff[2] = 0x00; /* status */
  56. x = sx1261_reg_r(SX1261_READ_REGISTER, buff, 18);
  57. if (x != LGW_REG_SUCCESS) {
  58. printf("ERROR: failed to read SX1261 PRAM version\n");
  59. return x;
  60. }
  61. /* Return full PRAM version string */
  62. buff[18] = '\0';
  63. strncpy(version_str, (char*)(buff + 3), 16); /* 15 bytes + terminating char */
  64. version_str[16] = '\0';
  65. return LGW_REG_SUCCESS;
  66. }
  67. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  68. int sx1261_get_status(uint8_t * status) {
  69. uint8_t buff[1];
  70. buff[0] = 0x00;
  71. sx1261_reg_r(SX1261_GET_STATUS, buff, 1);
  72. *status = buff[0] & 0x7E; /* ignore bit 0 & 7 */
  73. DEBUG_PRINTF("SX1261: %s: get_status: 0x%02X (0x%02X)\n", __FUNCTION__, *status, buff[0]);
  74. return LGW_REG_SUCCESS;
  75. }
  76. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  77. int sx1261_check_status(uint8_t expected_status) {
  78. int err;
  79. uint8_t status;
  80. err = sx1261_get_status(&status);
  81. if (err != LGW_REG_SUCCESS) {
  82. printf("ERROR: %s: failed to get status\n", __FUNCTION__);
  83. return LGW_REG_ERROR;
  84. }
  85. if (status != expected_status) {
  86. printf("ERROR: %s: SX1261 status is not as expected: got:0x%02X expected:0x%02X\n", __FUNCTION__, status, expected_status);
  87. return LGW_REG_ERROR;
  88. }
  89. return LGW_REG_SUCCESS;
  90. }
  91. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  92. const char * get_scan_status_str(const lgw_spectral_scan_status_t status) {
  93. switch (status) {
  94. case LGW_SPECTRAL_SCAN_STATUS_NONE:
  95. return "LGW_SPECTRAL_SCAN_STATUS_NONE";
  96. case LGW_SPECTRAL_SCAN_STATUS_ON_GOING:
  97. return "LGW_SPECTRAL_SCAN_STATUS_ON_GOING";
  98. case LGW_SPECTRAL_SCAN_STATUS_ABORTED:
  99. return "LGW_SPECTRAL_SCAN_STATUS_ABORTED";
  100. case LGW_SPECTRAL_SCAN_STATUS_COMPLETED:
  101. return "LGW_SPECTRAL_SCAN_STATUS_COMPLETED";
  102. default:
  103. return "LGW_SPECTRAL_SCAN_STATUS_UNKNOWN";
  104. }
  105. }
  106. /* -------------------------------------------------------------------------- */
  107. /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
  108. int sx1261_connect(lgw_com_type_t com_type, const char *com_path) {
  109. if (com_type == LGW_COM_SPI && com_path == NULL) {
  110. printf("ERROR: %s: unspecified COM path to connect to sx1261 radio\n", __FUNCTION__);
  111. return LGW_REG_ERROR;
  112. }
  113. return sx1261_com_open(com_type, com_path);
  114. }
  115. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  116. int sx1261_disconnect(void) {
  117. return sx1261_com_close();
  118. }
  119. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  120. int sx1261_reg_w(sx1261_op_code_t op_code, uint8_t *data, uint16_t size) {
  121. int com_stat;
  122. /* checking input parameters */
  123. CHECK_NULL(data);
  124. com_stat = sx1261_com_w(op_code, data, size);
  125. if (com_stat != LGW_COM_SUCCESS) {
  126. printf("ERROR: COM ERROR DURING SX1261 RADIO REGISTER WRITE\n");
  127. return LGW_REG_ERROR;
  128. } else {
  129. return LGW_REG_SUCCESS;
  130. }
  131. }
  132. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  133. int sx1261_reg_r(sx1261_op_code_t op_code, uint8_t *data, uint16_t size) {
  134. int com_stat;
  135. /* checking input parameters */
  136. CHECK_NULL(data);
  137. com_stat = sx1261_com_r(op_code, data, size);
  138. if (com_stat != LGW_COM_SUCCESS) {
  139. printf("ERROR: COM ERROR DURING SX1261 RADIO REGISTER READ\n");
  140. return LGW_REG_ERROR;
  141. } else {
  142. return LGW_REG_SUCCESS;
  143. }
  144. }
  145. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  146. int sx1261_load_pram(void) {
  147. int i, err;
  148. uint8_t buff[32];
  149. char pram_version[SX1261_PRAM_VERSION_FULL_SIZE];
  150. uint32_t val, addr;
  151. /* Set Radio in Standby mode */
  152. buff[0] = (uint8_t)SX1261_STDBY_RC;
  153. sx1261_reg_w(SX1261_SET_STANDBY, buff, 1);
  154. /* Check status */
  155. err = sx1261_check_status(SX1261_STATUS_MODE_STBY_RC | SX1261_STATUS_READY);
  156. if (err != LGW_REG_SUCCESS) {
  157. printf("ERROR: %s: SX1261 status error\n", __FUNCTION__);
  158. return -1;
  159. }
  160. err = sx1261_pram_get_version(pram_version);
  161. if (err != LGW_REG_SUCCESS) {
  162. printf("ERROR: %s: SX1261 failed to get pram version\n", __FUNCTION__);
  163. return -1;
  164. }
  165. printf("SX1261: PRAM version: %s\n", pram_version);
  166. /* Enable patch update */
  167. buff[0] = 0x06;
  168. buff[1] = 0x10;
  169. buff[2] = 0x10;
  170. err = sx1261_reg_w( SX1261_WRITE_REGISTER, buff, 3);
  171. CHECK_ERR(err);
  172. /* Load patch */
  173. for (i = 0; i < (int)PRAM_COUNT; i++) {
  174. val = pram[i];
  175. addr = 0x8000 + 4*i;
  176. buff[0] = (addr >> 8) & 0xFF;
  177. buff[1] = (addr >> 0) & 0xFF;
  178. buff[2] = (val >> 24) & 0xFF;
  179. buff[3] = (val >> 16) & 0xFF;
  180. buff[4] = (val >> 8) & 0xFF;
  181. buff[5] = (val >> 0) & 0xFF;
  182. err = sx1261_reg_w(SX1261_WRITE_REGISTER, buff, 6);
  183. CHECK_ERR(err);
  184. }
  185. /* Disable patch update */
  186. buff[0] = 0x06;
  187. buff[1] = 0x10;
  188. buff[2] = 0x00;
  189. err = sx1261_reg_w( SX1261_WRITE_REGISTER, buff, 3);
  190. CHECK_ERR(err);
  191. /* Update pram */
  192. buff[0] = 0;
  193. err = sx1261_reg_w(0xd9, buff, 0);
  194. CHECK_ERR(err);
  195. err = sx1261_pram_get_version(pram_version);
  196. if (err != LGW_REG_SUCCESS) {
  197. printf("ERROR: %s: SX1261 failed to get pram version\n", __FUNCTION__);
  198. return -1;
  199. }
  200. printf("SX1261: PRAM version: %s\n", pram_version);
  201. /* Check PRAM version (only last 4 bytes) */
  202. if (strncmp(pram_version + 11, sx1261_pram_version_string, 4) != 0) {
  203. printf("ERROR: SX1261 PRAM version mismatch (got:%s expected:%s)\n", pram_version + 11, sx1261_pram_version_string);
  204. return -1;
  205. }
  206. return 0;
  207. }
  208. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  209. int sx1261_calibrate(uint32_t freq_hz) {
  210. int err = LGW_REG_SUCCESS;
  211. uint8_t buff[16];
  212. buff[0] = 0x00;
  213. err = sx1261_reg_r(SX1261_GET_STATUS, buff, 1);
  214. CHECK_ERR(err);
  215. /* Run calibration */
  216. if ((freq_hz > 430E6) && (freq_hz < 440E6)) {
  217. buff[0] = 0x6B;
  218. buff[1] = 0x6F;
  219. } else if ((freq_hz > 470E6) && (freq_hz < 510E6)) {
  220. buff[0] = 0x75;
  221. buff[1] = 0x81;
  222. } else if ((freq_hz > 779E6) && (freq_hz < 787E6)) {
  223. buff[0] = 0xC1;
  224. buff[1] = 0xC5;
  225. } else if ((freq_hz > 863E6) && (freq_hz < 870E6)) {
  226. buff[0] = 0xD7;
  227. buff[1] = 0xDB;
  228. } else if ((freq_hz > 902E6) && (freq_hz < 928E6)) {
  229. buff[0] = 0xE1;
  230. buff[1] = 0xE9;
  231. } else {
  232. printf("ERROR: failed to calibrate sx1261 radio, frequency range not supported (%u)\n", freq_hz);
  233. return LGW_REG_ERROR;
  234. }
  235. err = sx1261_reg_w(SX1261_CALIBRATE_IMAGE, buff, 2);
  236. CHECK_ERR(err);
  237. /* Wait for calibration to complete */
  238. wait_ms(10);
  239. buff[0] = 0x00;
  240. buff[1] = 0x00;
  241. buff[2] = 0x00;
  242. err = sx1261_reg_r(SX1261_GET_DEVICE_ERRORS, buff, 3);
  243. CHECK_ERR(err);
  244. if (TAKE_N_BITS_FROM(buff[2], 4, 1) != 0) {
  245. printf("ERROR: sx1261 Image Calibration Error\n");
  246. return LGW_REG_ERROR;
  247. }
  248. return err;
  249. }
  250. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  251. int sx1261_setup(void) {
  252. int err;
  253. uint8_t buff[32];
  254. /* Set Radio in Standby mode */
  255. buff[0] = (uint8_t)SX1261_STDBY_RC;
  256. err = sx1261_reg_w(SX1261_SET_STANDBY, buff, 1);
  257. CHECK_ERR(err);
  258. /* Check radio status */
  259. err = sx1261_check_status(SX1261_STATUS_MODE_STBY_RC | SX1261_STATUS_READY);
  260. CHECK_ERR(err);
  261. /* Set Buffer Base address */
  262. buff[0] = 0x80;
  263. buff[1] = 0x80;
  264. err = sx1261_reg_w(SX1261_SET_BUFFER_BASE_ADDRESS, buff, 2);
  265. CHECK_ERR(err);
  266. /* sensi adjust */
  267. buff[0] = 0x08;
  268. buff[1] = 0xAC;
  269. buff[2] = 0xCB;
  270. err = sx1261_reg_w(SX1261_WRITE_REGISTER, buff, 3);
  271. CHECK_ERR(err);
  272. DEBUG_MSG("SX1261: setup for LBT / Spectral Scan done\n");
  273. return LGW_REG_SUCCESS;
  274. }
  275. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  276. int sx1261_set_rx_params(uint32_t freq_hz, uint8_t bandwidth) {
  277. int err;
  278. uint8_t buff[16];
  279. int32_t freq_reg;
  280. uint8_t fsk_bw_reg;
  281. /* performances variables */
  282. struct timeval tm;
  283. /* Record function start time */
  284. _meas_time_start(&tm);
  285. /* Set SPI write bulk mode to optimize speed on USB */
  286. err = sx1261_com_set_write_mode(LGW_COM_WRITE_MODE_BULK);
  287. CHECK_ERR(err);
  288. /* Disable any on-going spectral scan to free the sx1261 radio for LBT */
  289. err = sx1261_spectral_scan_abort();
  290. CHECK_ERR(err);
  291. /* Set FS */
  292. err = sx1261_reg_w(SX1261_SET_FS, buff, 0);
  293. CHECK_ERR(err);
  294. #if DEBUG_SX1261_GET_STATUS /* need to disable spi bulk mode if enable this check */
  295. /* Check radio status */
  296. err = sx1261_check_status(SX1261_STATUS_MODE_FS | SX1261_STATUS_READY);
  297. CHECK_ERR(err);
  298. #endif
  299. /* Set frequency */
  300. freq_reg = SX1261_FREQ_TO_REG(freq_hz);
  301. buff[0] = (uint8_t)(freq_reg >> 24);
  302. buff[1] = (uint8_t)(freq_reg >> 16);
  303. buff[2] = (uint8_t)(freq_reg >> 8);
  304. buff[3] = (uint8_t)(freq_reg >> 0);
  305. err = sx1261_reg_w(SX1261_SET_RF_FREQUENCY, buff, 4);
  306. CHECK_ERR(err);
  307. /* Configure RSSI averaging window */
  308. buff[0] = 0x08;
  309. buff[1] = 0x9B;
  310. buff[2] = 0x05 << 2;
  311. err = sx1261_reg_w(SX1261_WRITE_REGISTER, buff, 3);
  312. CHECK_ERR(err);
  313. /* Set PacketType */
  314. buff[0] = 0x00; /* FSK */
  315. err = sx1261_reg_w(SX1261_SET_PACKET_TYPE, buff, 1);
  316. CHECK_ERR(err);
  317. /* Set GFSK bandwidth */
  318. switch (bandwidth) {
  319. case BW_125KHZ:
  320. fsk_bw_reg = 0x0A; /* RX_BW_234300 Hz */
  321. break;
  322. case BW_250KHZ:
  323. fsk_bw_reg = 0x09; /* RX_BW_467000 Hz */
  324. break;
  325. default:
  326. printf("ERROR: %s: Cannot configure sx1261 for bandwidth %u\n", __FUNCTION__, bandwidth);
  327. return LGW_REG_ERROR;
  328. }
  329. /* Set modulation params for FSK */
  330. buff[0] = 0; // BR
  331. buff[1] = 0x14; // BR
  332. buff[2] = 0x00; // BR
  333. buff[3] = 0x00; // Gaussian BT disabled
  334. buff[4] = fsk_bw_reg;
  335. buff[5] = 0x02; // FDEV
  336. buff[6] = 0xE9; // FDEV
  337. buff[7] = 0x0F; // FDEV
  338. err = sx1261_reg_w(SX1261_SET_MODULATION_PARAMS, buff, 8);
  339. CHECK_ERR(err);
  340. /* Set packet params for FSK */
  341. buff[0] = 0x00; /* Preamble length MSB */
  342. buff[1] = 0x20; /* Preamble length LSB 32 bits*/
  343. buff[2] = 0x05; /* Preamble detector lenght 16 bits */
  344. buff[3] = 0x20; /* SyncWordLength 32 bits*/
  345. buff[4] = 0x00; /* AddrComp disabled */
  346. buff[5] = 0x01; /* PacketType variable size */
  347. buff[6] = 0xff; /* PayloadLength 255 bytes */
  348. buff[7] = 0x00; /* CRCType 1 Byte */
  349. buff[8] = 0x00; /* Whitening disabled*/
  350. err = sx1261_reg_w(SX1261_SET_PACKET_PARAMS, buff, 9);
  351. CHECK_ERR(err);
  352. /* Set Radio in Rx continuous mode */
  353. buff[0] = 0xFF;
  354. buff[1] = 0xFF;
  355. buff[2] = 0xFF;
  356. err = sx1261_reg_w(SX1261_SET_RX, buff, 3);
  357. CHECK_ERR(err);
  358. /* Flush write (USB BULK mode) */
  359. err = sx1261_com_flush();
  360. if (err != 0) {
  361. printf("ERROR: %s: Failed to flush sx1261 SPI\n", __FUNCTION__);
  362. return -1;
  363. }
  364. /* Setting back to SINGLE BULK write mode */
  365. err = sx1261_com_set_write_mode(LGW_COM_WRITE_MODE_SINGLE);
  366. CHECK_ERR(err);
  367. #if DEBUG_SX1261_GET_STATUS
  368. /* Check radio status */
  369. err = sx1261_check_status(SX1261_STATUS_MODE_RX | SX1261_STATUS_READY);
  370. CHECK_ERR(err);
  371. #endif
  372. DEBUG_PRINTF("SX1261: RX params set to %u Hz (bw:0x%02X)\n", freq_hz, bandwidth);
  373. _meas_time_stop(4, tm, __FUNCTION__);
  374. return LGW_REG_SUCCESS;
  375. }
  376. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  377. int sx1261_lbt_start(lgw_lbt_scan_time_t scan_time_us, int8_t threshold_dbm) {
  378. int err;
  379. uint8_t buff[16];
  380. uint16_t nb_scan;
  381. uint8_t threshold_reg = -2 * threshold_dbm;
  382. /* performances variables */
  383. struct timeval tm;
  384. /* Record function start time */
  385. _meas_time_start(&tm);
  386. switch (scan_time_us) {
  387. case LGW_LBT_SCAN_TIME_128_US:
  388. nb_scan = 24;
  389. break;
  390. case LGW_LBT_SCAN_TIME_5000_US:
  391. nb_scan = 715;
  392. break;
  393. default:
  394. printf("ERROR: wrong scan_time_us value\n");
  395. return -1;
  396. }
  397. #if DEBUG_SX1261_GET_STATUS
  398. /* Check radio status */
  399. err = sx1261_check_status(SX1261_STATUS_MODE_RX | SX1261_STATUS_READY);
  400. CHECK_ERR(err);
  401. #endif
  402. /* Configure LBT scan */
  403. buff[0] = 11; // intervall_rssi_read (10 => 7.68 usec,11 => 8.2 usec, 12 => 8.68 usec)
  404. buff[1] = (nb_scan >> 8) & 0xFF;
  405. buff[2] = (nb_scan >> 0) & 0xFF;
  406. buff[3] = threshold_reg;
  407. buff[4] = 1; // gpioId
  408. err = sx1261_reg_w(0x9a, buff, 5);
  409. CHECK_ERR(err);
  410. /* Wait for Scan Time before TX trigger request */
  411. wait_us((uint16_t)scan_time_us);
  412. DEBUG_PRINTF("SX1261: LBT started: scan time = %uus, threshold = %ddBm\n", (uint16_t)scan_time_us, threshold_dbm);
  413. _meas_time_stop(4, tm, __FUNCTION__);
  414. return LGW_REG_SUCCESS;
  415. }
  416. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  417. int sx1261_lbt_stop(void) {
  418. int err;
  419. uint8_t buff[16];
  420. /* performances variables */
  421. struct timeval tm;
  422. /* Record function start time */
  423. _meas_time_start(&tm);
  424. /* Disable LBT */
  425. buff[0] = 0x08;
  426. buff[1] = 0x9B;
  427. buff[2] = 0x00;
  428. err = sx1261_reg_w(SX1261_WRITE_REGISTER, buff, 3);
  429. CHECK_ERR(err);
  430. /* Set FS */
  431. err = sx1261_reg_w(SX1261_SET_FS, buff, 0);
  432. CHECK_ERR(err);
  433. DEBUG_MSG("SX1261: LBT stopped\n");
  434. _meas_time_stop(4, tm, __FUNCTION__);
  435. return LGW_REG_SUCCESS;
  436. }
  437. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  438. int sx1261_spectral_scan_start(uint16_t nb_scan) {
  439. int err;
  440. uint8_t buff[4]; /* 66 bytes for spectral scan results + 2 bytes register address + 1 dummy byte for reading */
  441. /* performances variables */
  442. struct timeval tm;
  443. /* Record function start time */
  444. _meas_time_start(&tm);
  445. /* Start spectral scan */
  446. buff[0] = (nb_scan >> 8) & 0xFF; /* nb_scan MSB */
  447. buff[1] = (nb_scan >> 0) & 0xFF; /* nb_scan LSB */
  448. buff[2] = 11; /* interval between scans - 8.2 us */
  449. err = sx1261_reg_w(0x9b, buff, 9);
  450. CHECK_ERR(err);
  451. DEBUG_MSG("INFO: Spectral Scan started...\n");
  452. _meas_time_stop(4, tm, __FUNCTION__);
  453. return LGW_REG_SUCCESS;
  454. }
  455. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  456. int sx1261_spectral_scan_get_results(int8_t rssi_offset, int16_t * levels_dbm, uint16_t * results) {
  457. int err, i;
  458. uint8_t buff[69]; /* 66 bytes for spectral scan results + 2 bytes register address + 1 dummy byte for reading */
  459. /* performances variables */
  460. struct timeval tm;
  461. /* Record function start time */
  462. _meas_time_start(&tm);
  463. /* Check input parameters */
  464. CHECK_NULL(levels_dbm);
  465. CHECK_NULL(results);
  466. /* Get the results (66 bytes) */
  467. buff[0] = 0x04;
  468. buff[1] = 0x01;
  469. buff[2] = 0x00; /* dummy */
  470. for (i = 3; i < (66 + 3) ; i++) {
  471. buff[i] = 0x00;
  472. }
  473. err = sx1261_reg_r(SX1261_READ_REGISTER, buff, 66 + 3);
  474. CHECK_ERR(err);
  475. /* Copy the results in the given buffers */
  476. /* The number of points measured ABOVE each threshold */
  477. for (i = 0; i < 32; i++) {
  478. levels_dbm[i] = -i*4 + rssi_offset;
  479. results[i] = (uint16_t)((buff[3 + i*2] << 8) | buff[3 + i*2 + 1]);
  480. }
  481. /* The number of points measured BELOW the lower threshold */
  482. levels_dbm[32] = -31*4 + rssi_offset;
  483. results[32] = (uint16_t)((buff[3 + 32*2] << 8) + buff[3 + 32*2 + 1]);
  484. _meas_time_stop(4, tm, __FUNCTION__);
  485. return LGW_REG_SUCCESS;
  486. }
  487. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  488. int sx1261_spectral_scan_status(lgw_spectral_scan_status_t * status) {
  489. int err;
  490. uint8_t buff[16];
  491. /* performances variables */
  492. struct timeval tm;
  493. CHECK_NULL(status);
  494. /* Record function start time */
  495. _meas_time_start(&tm);
  496. /* Get status */
  497. buff[0] = 0x07;
  498. buff[1] = 0xCD;
  499. buff[2] = 0x00; /* dummy */
  500. buff[3] = 0x00; /* read value holder */
  501. err = sx1261_reg_r(SX1261_READ_REGISTER, buff, 4);
  502. CHECK_ERR(err);
  503. switch (buff[3]) {
  504. case 0x00:
  505. *status = LGW_SPECTRAL_SCAN_STATUS_NONE;
  506. break;
  507. case 0x0F:
  508. *status = LGW_SPECTRAL_SCAN_STATUS_ON_GOING;
  509. break;
  510. case 0xF0:
  511. *status = LGW_SPECTRAL_SCAN_STATUS_ABORTED;
  512. break;
  513. case 0xFF:
  514. *status = LGW_SPECTRAL_SCAN_STATUS_COMPLETED;
  515. break;
  516. default:
  517. *status = LGW_SPECTRAL_SCAN_STATUS_UNKNOWN;
  518. break;
  519. }
  520. DEBUG_PRINTF("INFO: %s: %s\n", __FUNCTION__, get_scan_status_str(*status));
  521. _meas_time_stop(4, tm, __FUNCTION__);
  522. return LGW_REG_SUCCESS;
  523. }
  524. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  525. int sx1261_spectral_scan_abort(void) {
  526. int err;
  527. uint8_t buff[16];
  528. /* performances variables */
  529. struct timeval tm;
  530. /* Record function start time */
  531. _meas_time_start(&tm);
  532. /* Disable LBT */
  533. buff[0] = 0x08;
  534. buff[1] = 0x9B;
  535. buff[2] = 0x00;
  536. err = sx1261_reg_w(SX1261_WRITE_REGISTER, buff, 3);
  537. CHECK_ERR(err);
  538. DEBUG_MSG("SX1261: spectral scan aborted\n");
  539. _meas_time_stop(4, tm, __FUNCTION__);
  540. return LGW_REG_SUCCESS;
  541. }
  542. /* --- EOF ------------------------------------------------------------------ */