loragw_sx1302_rx.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /*
  2. / _____) _ | |
  3. ( (____ _____ ____ _| |_ _____ ____| |__
  4. \____ \| ___ | (_ _) ___ |/ ___) _ \
  5. _____) ) ____| | | || |_| ____( (___| | | |
  6. (______/|_____)_|_|_| \__)_____)\____)_| |_|
  7. (C)2019 Semtech
  8. Description:
  9. SX1302 RX buffer Hardware Abstraction Layer
  10. License: Revised BSD License, see LICENSE.TXT file include in the project
  11. */
  12. /* -------------------------------------------------------------------------- */
  13. /* --- DEPENDANCIES --------------------------------------------------------- */
  14. #include <stdint.h> /* C99 types */
  15. #include <stdio.h> /* printf fprintf */
  16. #include <string.h> /* memset */
  17. #include <assert.h> /* assert */
  18. #include "loragw_aux.h"
  19. #include "loragw_reg.h"
  20. #include "loragw_sx1302_rx.h"
  21. #include "loragw_sx1302_timestamp.h"
  22. /* -------------------------------------------------------------------------- */
  23. /* --- PRIVATE MACROS ------------------------------------------------------- */
  24. #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
  25. #if DEBUG_SX1302 == 1
  26. #define DEBUG_MSG(str) fprintf(stdout, str)
  27. #define DEBUG_PRINTF(fmt, args...) fprintf(stdout, fmt, args)
  28. #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;}
  29. #else
  30. #define DEBUG_MSG(str)
  31. #define DEBUG_PRINTF(fmt, args...)
  32. #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;}
  33. #endif
  34. #define SX1302_PKT_PAYLOAD_LENGTH(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 2], 0, 8)
  35. #define SX1302_PKT_CHANNEL(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 3], 0, 8)
  36. #define SX1302_PKT_CRC_EN(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 4], 0, 1)
  37. #define SX1302_PKT_CODING_RATE(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 4], 1, 3)
  38. #define SX1302_PKT_DATARATE(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 4], 4, 4)
  39. #define SX1302_PKT_MODEM_ID(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 5], 0, 8)
  40. #define SX1302_PKT_FREQ_OFFSET_7_0(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 6], 0, 8)
  41. #define SX1302_PKT_FREQ_OFFSET_15_8(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 7], 0, 8)
  42. #define SX1302_PKT_FREQ_OFFSET_19_16(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 8], 0, 4)
  43. #define SX1302_PKT_CRC_ERROR(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 9], 0, 1)
  44. #define SX1302_PKT_SYNC_ERROR(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 9], 2, 1)
  45. #define SX1302_PKT_HEADER_ERROR(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 9], 3, 1)
  46. #define SX1302_PKT_TIMING_SET(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 9], 4, 1)
  47. #define SX1302_PKT_SNR_AVG(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 10], 0, 8)
  48. #define SX1302_PKT_RSSI_CHAN(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 11], 0, 8)
  49. #define SX1302_PKT_RSSI_SIG(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 12], 0, 8)
  50. #define SX1302_PKT_RSSI_CHAN_MAX_NEG_DELTA(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 13], 0, 4)
  51. #define SX1302_PKT_RSSI_CHAN_MAX_POS_DELTA(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 13], 4, 4)
  52. #define SX1302_PKT_RSSI_SIG_MAX_NEG_DELTA(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 14], 0, 4)
  53. #define SX1302_PKT_RSSI_SIG_MAX_POS_DELTA(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 14], 4, 4)
  54. #define SX1302_PKT_TIMESTAMP_7_0(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 15], 0, 8)
  55. #define SX1302_PKT_TIMESTAMP_15_8(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 16], 0, 8)
  56. #define SX1302_PKT_TIMESTAMP_23_16(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 17], 0, 8)
  57. #define SX1302_PKT_TIMESTAMP_31_24(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 18], 0, 8)
  58. #define SX1302_PKT_CRC_PAYLOAD_7_0(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 19], 0, 8)
  59. #define SX1302_PKT_CRC_PAYLOAD_15_8(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 20], 0, 8)
  60. #define SX1302_PKT_NUM_TS_METRICS(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 21], 0, 8)
  61. /* -------------------------------------------------------------------------- */
  62. /* --- PRIVATE TYPES -------------------------------------------------------- */
  63. /* -------------------------------------------------------------------------- */
  64. /* --- PRIVATE CONSTANTS ---------------------------------------------------- */
  65. /* RX buffer packet structure */
  66. #define SX1302_PKT_SYNCWORD_BYTE_0 0xA5
  67. #define SX1302_PKT_SYNCWORD_BYTE_1 0xC0
  68. #define SX1302_PKT_HEAD_METADATA 9
  69. #define SX1302_PKT_TAIL_METADATA 14
  70. /* modem IDs */
  71. #define SX1302_LORA_MODEM_ID_MAX 15
  72. #define SX1302_LORA_STD_MODEM_ID 16
  73. #define SX1302_FSK_MODEM_ID 17
  74. /* -------------------------------------------------------------------------- */
  75. /* --- PRIVATE VARIABLES ---------------------------------------------------- */
  76. /* -------------------------------------------------------------------------- */
  77. /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
  78. /* -------------------------------------------------------------------------- */
  79. /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
  80. /* -------------------------------------------------------------------------- */
  81. /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
  82. int rx_buffer_new(rx_buffer_t * self) {
  83. /* Check input params */
  84. CHECK_NULL(self);
  85. /* Initialize members */
  86. memset(self->buffer, 0, sizeof self->buffer);
  87. self->buffer_size = 0;
  88. self->buffer_index = 0;
  89. self->buffer_pkt_nb = 0;
  90. return LGW_REG_SUCCESS;
  91. }
  92. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  93. int rx_buffer_del(rx_buffer_t * self) {
  94. /* Check input params */
  95. CHECK_NULL(self);
  96. /* Reset index & size */
  97. self->buffer_size = 0;
  98. self->buffer_index = 0;
  99. self->buffer_pkt_nb = 0;
  100. return LGW_REG_SUCCESS;
  101. }
  102. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  103. int rx_buffer_fetch(rx_buffer_t * self) {
  104. int i, res;
  105. uint8_t buff[2];
  106. uint8_t payload_len;
  107. uint16_t next_pkt_idx;
  108. int idx;
  109. uint16_t nb_bytes_1, nb_bytes_2;
  110. /* Check input params */
  111. CHECK_NULL(self);
  112. /* Check if there is data in the FIFO */
  113. lgw_reg_rb(SX1302_REG_RX_TOP_RX_BUFFER_NB_BYTES_MSB_RX_BUFFER_NB_BYTES, buff, sizeof buff);
  114. nb_bytes_1 = (buff[0] << 8) | (buff[1] << 0);
  115. /* Workaround for multi-byte read issue: read again and ensure new read is not lower than the previous one */
  116. lgw_reg_rb(SX1302_REG_RX_TOP_RX_BUFFER_NB_BYTES_MSB_RX_BUFFER_NB_BYTES, buff, sizeof buff);
  117. nb_bytes_2 = (buff[0] << 8) | (buff[1] << 0);
  118. self->buffer_size = (nb_bytes_2 > nb_bytes_1) ? nb_bytes_2 : nb_bytes_1;
  119. /* Fetch bytes from fifo if any */
  120. if (self->buffer_size > 0) {
  121. DEBUG_MSG ("-----------------\n");
  122. DEBUG_PRINTF("%s: nb_bytes to be fetched: %u (%u %u)\n", __FUNCTION__, self->buffer_size, buff[1], buff[0]);
  123. memset(self->buffer, 0, sizeof self->buffer);
  124. res = lgw_mem_rb(0x4000, self->buffer, self->buffer_size, true);
  125. if (res != LGW_REG_SUCCESS) {
  126. printf("ERROR: Failed to read RX buffer, SPI error\n");
  127. return LGW_REG_ERROR;
  128. }
  129. /* print debug info */
  130. DEBUG_MSG("RX_BUFFER: ");
  131. for (i = 0; i < self->buffer_size; i++) {
  132. DEBUG_PRINTF("%02X ", self->buffer[i]);
  133. }
  134. DEBUG_MSG("\n");
  135. /* Sanity check: is there at least 1 complete packet in the buffer */
  136. if (self->buffer_size < (SX1302_PKT_HEAD_METADATA + SX1302_PKT_TAIL_METADATA)) {
  137. printf("WARNING: not enough data to have a complete packet, discard rx_buffer\n");
  138. return rx_buffer_del(self);
  139. }
  140. /* Sanity check: is there a syncword at 0 ? If not, move to the first syncword found */
  141. idx = 0;
  142. while (idx <= (self->buffer_size - 2)) {
  143. if ((self->buffer[idx] == SX1302_PKT_SYNCWORD_BYTE_0) && (self->buffer[idx + 1] == SX1302_PKT_SYNCWORD_BYTE_1)) {
  144. DEBUG_PRINTF("INFO: syncword found at idx %d\n", idx);
  145. break;
  146. } else {
  147. printf("INFO: syncword not found at idx %d\n", idx);
  148. idx += 1;
  149. }
  150. }
  151. if (idx > self->buffer_size - 2) {
  152. printf("WARNING: no syncword found, discard rx_buffer\n");
  153. return rx_buffer_del(self);
  154. }
  155. if (idx != 0) {
  156. printf("INFO: re-sync rx_buffer at idx %d\n", idx);
  157. memmove((void *)(self->buffer), (void *)(self->buffer + idx), self->buffer_size - idx);
  158. self->buffer_size -= idx;
  159. }
  160. /* Rewind and parse buffer to get the number of packet fetched */
  161. idx = 0;
  162. while (idx < self->buffer_size) {
  163. if ((self->buffer[idx] != SX1302_PKT_SYNCWORD_BYTE_0) || (self->buffer[idx + 1] != SX1302_PKT_SYNCWORD_BYTE_1)) {
  164. printf("WARNING: syncword not found at idx %d, discard the rx_buffer\n", idx);
  165. return rx_buffer_del(self);
  166. }
  167. /* One packet found in the buffer */
  168. self->buffer_pkt_nb += 1;
  169. /* Compute the number of bytes for this packet */
  170. payload_len = SX1302_PKT_PAYLOAD_LENGTH(self->buffer, idx);
  171. next_pkt_idx = SX1302_PKT_HEAD_METADATA +
  172. payload_len +
  173. SX1302_PKT_TAIL_METADATA +
  174. (2 * SX1302_PKT_NUM_TS_METRICS(self->buffer, idx + payload_len));
  175. /* Move to next packet */
  176. idx += (int)next_pkt_idx;
  177. }
  178. }
  179. /* Initialize the current buffer index to iterate on */
  180. self->buffer_index = 0;
  181. return LGW_REG_SUCCESS;
  182. }
  183. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  184. int rx_buffer_pop(rx_buffer_t * self, rx_packet_t * pkt) {
  185. int i;
  186. uint8_t checksum_rcv, checksum_calc = 0;
  187. uint16_t checksum_idx;
  188. uint16_t pkt_num_bytes;
  189. /* Check input params */
  190. CHECK_NULL(self);
  191. CHECK_NULL(pkt);
  192. /* Is there any data to be parsed ? */
  193. if (self->buffer_index >= self->buffer_size) {
  194. DEBUG_MSG("INFO: No more data to be parsed\n");
  195. return LGW_REG_ERROR;
  196. }
  197. /* Get pkt sync words */
  198. if ((self->buffer[self->buffer_index] != SX1302_PKT_SYNCWORD_BYTE_0) || (self->buffer[self->buffer_index + 1] != SX1302_PKT_SYNCWORD_BYTE_1)) {
  199. return LGW_REG_ERROR;
  200. }
  201. DEBUG_PRINTF("INFO: pkt syncword found at index %u\n", self->buffer_index);
  202. /* Get payload length */
  203. pkt->rxbytenb_modem = SX1302_PKT_PAYLOAD_LENGTH(self->buffer, self->buffer_index);
  204. /* Get fine timestamp metrics */
  205. pkt->num_ts_metrics_stored = SX1302_PKT_NUM_TS_METRICS(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
  206. /* Calculate the total number of bytes in the packet */
  207. pkt_num_bytes = SX1302_PKT_HEAD_METADATA + pkt->rxbytenb_modem + SX1302_PKT_TAIL_METADATA + (2 * pkt->num_ts_metrics_stored);
  208. /* Check if we have a complete packet in the rx buffer fetched */
  209. if((self->buffer_index + pkt_num_bytes) > self->buffer_size) {
  210. printf("WARNING: aborting truncated message (size=%u)\n", self->buffer_size);
  211. return LGW_REG_WARNING;
  212. }
  213. /* Get the checksum as received in the RX buffer */
  214. checksum_idx = pkt_num_bytes - 1;
  215. checksum_rcv = self->buffer[self->buffer_index + pkt_num_bytes - 1];
  216. /* Calculate the checksum from the actual payload bytes received */
  217. for (i = 0; i < (int)checksum_idx; i++) {
  218. checksum_calc += self->buffer[self->buffer_index + i];
  219. }
  220. /* Check if the checksum is correct */
  221. if (checksum_rcv != checksum_calc) {
  222. printf("WARNING: checksum failed (got:0x%02X calc:0x%02X)\n", checksum_rcv, checksum_calc);
  223. return LGW_REG_WARNING;
  224. } else {
  225. DEBUG_PRINTF("Packet checksum OK (0x%02X)\n", checksum_rcv);
  226. }
  227. /* Parse packet metadata */
  228. pkt->modem_id = SX1302_PKT_MODEM_ID(self->buffer, self->buffer_index);
  229. pkt->rx_channel_in = SX1302_PKT_CHANNEL(self->buffer, self->buffer_index);
  230. pkt->crc_en = SX1302_PKT_CRC_EN(self->buffer, self->buffer_index);
  231. pkt->payload_crc_error = SX1302_PKT_CRC_ERROR(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
  232. pkt->sync_error = SX1302_PKT_SYNC_ERROR(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
  233. pkt->header_error = SX1302_PKT_HEADER_ERROR(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
  234. pkt->timing_set = SX1302_PKT_TIMING_SET(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
  235. pkt->coding_rate = SX1302_PKT_CODING_RATE(self->buffer, self->buffer_index);
  236. pkt->rx_rate_sf = SX1302_PKT_DATARATE(self->buffer, self->buffer_index);
  237. pkt->rssi_chan_avg = SX1302_PKT_RSSI_CHAN(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
  238. pkt->rssi_signal_avg = SX1302_PKT_RSSI_SIG(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
  239. pkt->rx_crc16_value = (uint16_t)((SX1302_PKT_CRC_PAYLOAD_7_0(self->buffer, self->buffer_index + pkt->rxbytenb_modem) << 0) & 0x00FF);
  240. pkt->rx_crc16_value |= (uint16_t)((SX1302_PKT_CRC_PAYLOAD_15_8(self->buffer, self->buffer_index + pkt->rxbytenb_modem) << 8) & 0xFF00);
  241. pkt->snr_average = (int8_t)SX1302_PKT_SNR_AVG(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
  242. pkt->frequency_offset_error = (int32_t)((SX1302_PKT_FREQ_OFFSET_19_16(self->buffer, self->buffer_index) << 16) | (SX1302_PKT_FREQ_OFFSET_15_8(self->buffer, self->buffer_index) << 8) | (SX1302_PKT_FREQ_OFFSET_7_0(self->buffer, self->buffer_index) << 0));
  243. if (pkt->frequency_offset_error >= (1<<19)) { /* Handle signed value on 20bits */
  244. pkt->frequency_offset_error = (pkt->frequency_offset_error - (1<<20));
  245. }
  246. /* Packet timestamp (32MHz ) */
  247. pkt->timestamp_cnt = (uint32_t)((SX1302_PKT_TIMESTAMP_7_0(self->buffer, self->buffer_index + pkt->rxbytenb_modem) << 0) & 0x000000FF);
  248. pkt->timestamp_cnt |= (uint32_t)((SX1302_PKT_TIMESTAMP_15_8(self->buffer, self->buffer_index + pkt->rxbytenb_modem) << 8) & 0x0000FF00);
  249. pkt->timestamp_cnt |= (uint32_t)((SX1302_PKT_TIMESTAMP_23_16(self->buffer, self->buffer_index + pkt->rxbytenb_modem) << 16) & 0x00FF0000);
  250. pkt->timestamp_cnt |= (uint32_t)((SX1302_PKT_TIMESTAMP_31_24(self->buffer, self->buffer_index + pkt->rxbytenb_modem) << 24) & 0xFF000000);
  251. /* TS metrics: it is expected the nb_symbols parameter is set to 0 here */
  252. for (i = 0; i < (pkt->num_ts_metrics_stored * 2); i++) {
  253. pkt->timestamp_avg[i] = (int8_t)SX1302_PKT_NUM_TS_METRICS(self->buffer, self->buffer_index + pkt->rxbytenb_modem + 1 + i);
  254. pkt->timestamp_stddev[i] = 0; /* no stddev when nb_symbols == 0 */
  255. }
  256. DEBUG_MSG ("-----------------\n");
  257. DEBUG_PRINTF(" modem: %u\n", pkt->modem_id);
  258. DEBUG_PRINTF(" chan: %u\n", pkt->rx_channel_in);
  259. DEBUG_PRINTF(" size: %u\n", pkt->rxbytenb_modem);
  260. DEBUG_PRINTF(" crc_en: %u\n", pkt->crc_en);
  261. DEBUG_PRINTF(" crc_err: %u\n", pkt->payload_crc_error);
  262. DEBUG_PRINTF(" sync_err: %u\n", pkt->sync_error);
  263. DEBUG_PRINTF(" hdr_err: %u\n", pkt->header_error);
  264. DEBUG_PRINTF(" timing_set: %u\n", pkt->timing_set);
  265. DEBUG_PRINTF(" codr: %u\n", pkt->coding_rate);
  266. DEBUG_PRINTF(" datr: %u\n", pkt->rx_rate_sf);
  267. DEBUG_PRINTF(" num_ts: %u\n", pkt->num_ts_metrics_stored);
  268. if (pkt->num_ts_metrics_stored > 0) {
  269. DEBUG_MSG(" ts_avg: ");
  270. for (i = 0; i < (pkt->num_ts_metrics_stored * 2); i++) {
  271. DEBUG_PRINTF("%d ", pkt->timestamp_avg[i]);
  272. }
  273. DEBUG_MSG("\n");
  274. DEBUG_MSG(" ts_stdev: NONE (nb_symbols=0)\n");
  275. }
  276. DEBUG_MSG ("-----------------\n");
  277. /* Sanity checks: check the range of few metadata */
  278. if (pkt->modem_id > SX1302_FSK_MODEM_ID) {
  279. printf("ERROR: modem_id is out of range - %u\n", pkt->modem_id);
  280. return LGW_REG_ERROR;
  281. } else {
  282. if (pkt->modem_id <= SX1302_LORA_STD_MODEM_ID) { /* LoRa modems */
  283. if (pkt->rx_channel_in > 9) {
  284. printf("ERROR: channel is out of range - %u\n", pkt->rx_channel_in);
  285. return LGW_REG_ERROR;
  286. }
  287. if ((pkt->rx_rate_sf < 5) || (pkt->rx_rate_sf > 12)) {
  288. printf("ERROR: SF is out of range - %u\n", pkt->rx_rate_sf);
  289. return LGW_REG_ERROR;
  290. }
  291. } else { /* FSK modem */
  292. /* TODO: not checked */
  293. }
  294. }
  295. /* Parse & copy payload in packet struct */
  296. memcpy((void *)pkt->payload, (void *)(&(self->buffer[self->buffer_index + SX1302_PKT_HEAD_METADATA])), pkt->rxbytenb_modem);
  297. /* Move buffer index toward next message */
  298. self->buffer_index += (SX1302_PKT_HEAD_METADATA + pkt->rxbytenb_modem + SX1302_PKT_TAIL_METADATA + (2 * pkt->num_ts_metrics_stored));
  299. /* Update the number of packets currently stored in the rx_buffer */
  300. self->buffer_pkt_nb -= 1;
  301. return LGW_REG_SUCCESS;
  302. }
  303. /* -------------------------------------------------------------------------- */
  304. /* --- DEBUG FUNCTIONS DEFINITION ------------------------------------------- */
  305. uint16_t rx_buffer_read_ptr_addr(void) {
  306. int32_t val;
  307. uint16_t addr;
  308. lgw_reg_r(SX1302_REG_RX_TOP_RX_BUFFER_LAST_ADDR_READ_MSB_LAST_ADDR_READ, &val); /* mandatory to read MSB first */
  309. addr = (uint16_t)(val << 8);
  310. lgw_reg_r(SX1302_REG_RX_TOP_RX_BUFFER_LAST_ADDR_READ_LSB_LAST_ADDR_READ, &val);
  311. addr |= (uint16_t)val;
  312. return addr;
  313. }
  314. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  315. uint16_t rx_buffer_write_ptr_addr(void) {
  316. int32_t val;
  317. uint16_t addr;
  318. lgw_reg_r(SX1302_REG_RX_TOP_RX_BUFFER_LAST_ADDR_WRITE_MSB_LAST_ADDR_WRITE, &val); /* mandatory to read MSB first */
  319. addr = (uint16_t)(val << 8);
  320. lgw_reg_r(SX1302_REG_RX_TOP_RX_BUFFER_LAST_ADDR_WRITE_LSB_LAST_ADDR_WRITE, &val);
  321. addr |= (uint16_t)val;
  322. return addr;
  323. }
  324. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  325. void rx_buffer_dump(FILE * file, uint16_t start_addr, uint16_t end_addr) {
  326. int i;
  327. uint8_t rx_buffer_debug[4096];
  328. printf("Dumping %u bytes, from 0x%X to 0x%X\n", end_addr - start_addr + 1, start_addr, end_addr);
  329. memset(rx_buffer_debug, 0, sizeof rx_buffer_debug);
  330. lgw_reg_w(SX1302_REG_RX_TOP_RX_BUFFER_DIRECT_RAM_IF, 1);
  331. lgw_mem_rb(0x4000 + start_addr, rx_buffer_debug, end_addr - start_addr + 1, false);
  332. lgw_reg_w(SX1302_REG_RX_TOP_RX_BUFFER_DIRECT_RAM_IF, 0);
  333. for (i = 0; i < (end_addr - start_addr + 1); i++) {
  334. if (file == NULL) {
  335. printf("%02X ", rx_buffer_debug[i]);
  336. } else {
  337. fprintf(file, "%02X ", rx_buffer_debug[i]);
  338. }
  339. }
  340. if (file == NULL) {
  341. printf("\n");
  342. } else {
  343. fprintf(file, "\n");
  344. }
  345. /* Switching to direct-access memory could lead to corruption, so to be done only for debugging */
  346. assert(0);
  347. }
  348. /* --- EOF ------------------------------------------------------------------ */