loragw_aux.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. / _____) _ | |
  3. ( (____ _____ ____ _| |_ _____ ____| |__
  4. \____ \| ___ | (_ _) ___ |/ ___) _ \
  5. _____) ) ____| | | || |_| ____( (___| | | |
  6. (______/|_____)_|_|_| \__)_____)\____)_| |_|
  7. (C)2019 Semtech
  8. Description:
  9. LoRa concentrator HAL auxiliary functions
  10. License: Revised BSD License, see LICENSE.TXT file include in the project
  11. */
  12. /* -------------------------------------------------------------------------- */
  13. /* --- DEPENDANCIES --------------------------------------------------------- */
  14. /* fix an issue between POSIX and C99 */
  15. #if __STDC_VERSION__ >= 199901L
  16. #define _XOPEN_SOURCE 600
  17. #else
  18. #define _XOPEN_SOURCE 500
  19. #endif
  20. #include <stdio.h> /* printf fprintf */
  21. #include <time.h> /* clock_nanosleep */
  22. #include <math.h> /* pow, ceil */
  23. #include "loragw_aux.h"
  24. #include "loragw_hal.h"
  25. /* -------------------------------------------------------------------------- */
  26. /* --- PRIVATE MACROS ------------------------------------------------------- */
  27. #if DEBUG_AUX == 1
  28. #define DEBUG_MSG(str) fprintf(stdout, str)
  29. #define DEBUG_PRINTF(fmt, args...) fprintf(stdout,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
  30. #else
  31. #define DEBUG_MSG(str)
  32. #define DEBUG_PRINTF(fmt, args...)
  33. #endif
  34. /* -------------------------------------------------------------------------- */
  35. /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
  36. void wait_us(unsigned long delay_us) {
  37. struct timespec dly;
  38. struct timespec rem;
  39. dly.tv_sec = delay_us / 1000000;
  40. dly.tv_nsec = (delay_us % 1000000) * 1000;
  41. DEBUG_PRINTF("NOTE dly: %ld sec %ld ns\n", dly.tv_sec, dly.tv_nsec);
  42. while ((dly.tv_sec > 0) || (dly.tv_nsec > 1000)) {
  43. /*
  44. rem is set ONLY if clock_nanosleep is interrupted (eg. by a signal).
  45. Must be zeroed each time or will get into an infinite loop after an IT.
  46. */
  47. rem.tv_sec = 0;
  48. rem.tv_nsec = 0;
  49. clock_nanosleep(CLOCK_MONOTONIC, 0, &dly, &rem);
  50. DEBUG_PRINTF("NOTE remain: %ld sec %ld ns\n", rem.tv_sec, rem.tv_nsec);
  51. dly = rem;
  52. }
  53. return;
  54. }
  55. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  56. void wait_ms(unsigned long delay_ms) {
  57. struct timespec dly;
  58. struct timespec rem;
  59. dly.tv_sec = delay_ms / 1000;
  60. dly.tv_nsec = ((long)delay_ms % 1000) * 1000000;
  61. DEBUG_PRINTF("NOTE dly: %ld sec %ld ns\n", dly.tv_sec, dly.tv_nsec);
  62. if((dly.tv_sec > 0) || ((dly.tv_sec == 0) && (dly.tv_nsec > 100000))) {
  63. clock_nanosleep(CLOCK_MONOTONIC, 0, &dly, &rem);
  64. DEBUG_PRINTF("NOTE remain: %ld sec %ld ns\n", rem.tv_sec, rem.tv_nsec);
  65. }
  66. return;
  67. }
  68. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  69. uint32_t lora_packet_time_on_air(const uint8_t bw, const uint8_t sf, const uint8_t cr, const uint16_t n_symbol_preamble,
  70. const bool no_header, const bool no_crc, const uint8_t size,
  71. double * out_nb_symbols, uint32_t * out_nb_symbols_payload, uint16_t * out_t_symbol_us) {
  72. uint8_t H, DE, n_bit_crc;
  73. uint8_t bw_pow;
  74. uint16_t t_symbol_us;
  75. double n_symbol;
  76. uint32_t toa_us, n_symbol_payload;
  77. /* Check input parameters */
  78. if (IS_LORA_DR(sf) == false) {
  79. printf("ERROR: wrong datarate - %s\n", __FUNCTION__);
  80. return 0;
  81. }
  82. if (IS_LORA_BW(bw) == false) {
  83. printf("ERROR: wrong bandwidth - %s\n", __FUNCTION__);
  84. return 0;
  85. }
  86. if (IS_LORA_CR(cr) == false) {
  87. printf("ERROR: wrong coding rate - %s\n", __FUNCTION__);
  88. return 0;
  89. }
  90. /* Get bandwidth 125KHz divider*/
  91. switch (bw) {
  92. case BW_125KHZ:
  93. bw_pow = 1;
  94. break;
  95. case BW_250KHZ:
  96. bw_pow = 2;
  97. break;
  98. case BW_500KHZ:
  99. bw_pow = 4;
  100. break;
  101. default:
  102. printf("ERROR: unsupported bandwith 0x%02X (%s)\n", bw, __FUNCTION__);
  103. return 0;
  104. }
  105. /* Duration of 1 symbol */
  106. t_symbol_us = (1 << sf) * 8 / bw_pow; /* 2^SF / BW , in microseconds */
  107. /* Packet parameters */
  108. H = (no_header == false) ? 1 : 0; /* header is always enabled, except for beacons */
  109. DE = (sf >= 11) ? 1 : 0; /* Low datarate optimization enabled for SF11 and SF12 */
  110. n_bit_crc = (no_crc == false) ? 16 : 0;
  111. /* Number of symbols in the payload */
  112. n_symbol_payload = ceil( MAX( (double)( 8 * size + n_bit_crc - 4*sf + ((sf >= 7) ? 8 : 0) + 20*H ), 0.0) /
  113. (double)( 4 * (sf - 2*DE)) )
  114. * ( cr + 4 ); /* Explicitely cast to double to keep precision of the division */
  115. /* number of symbols in packet */
  116. n_symbol = (double)n_symbol_preamble + ((sf >= 7) ? 4.25 : 6.25) + 8.0 + (double)n_symbol_payload;
  117. /* Duration of packet in microseconds */
  118. toa_us = (uint32_t)( (double)n_symbol * (double)t_symbol_us );
  119. DEBUG_PRINTF("INFO: LoRa packet ToA: %u us (n_symbol:%f, t_symbol_us:%u)\n", toa_us, n_symbol, t_symbol_us);
  120. /* Return details if required */
  121. if (out_nb_symbols != NULL) {
  122. *out_nb_symbols = n_symbol;
  123. }
  124. if (out_nb_symbols_payload != NULL) {
  125. *out_nb_symbols_payload = n_symbol_payload;
  126. }
  127. if (out_t_symbol_us != NULL) {
  128. *out_t_symbol_us = t_symbol_us;
  129. }
  130. return toa_us;
  131. }
  132. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  133. #pragma GCC diagnostic push
  134. #pragma GCC diagnostic ignored "-Wunused-parameter"
  135. void _meas_time_start(struct timeval *tm)
  136. {
  137. #if (DEBUG_PaERF > 0) && (DEBUG_PERF <= 5)
  138. gettimeofday(tm, NULL);
  139. #endif
  140. }
  141. void _meas_time_stop(int debug_level, struct timeval start_time, const char *str)
  142. {
  143. #if (DEBUG_PERF > 0) && (DEBUG_PERF <= 5)
  144. struct timeval tm;
  145. double time_ms;
  146. char *indent[] = { "", " ..", " ....", " ......", " ........" };
  147. gettimeofday(&tm, NULL);
  148. time_ms = (tm.tv_sec - start_time.tv_sec) * 1000.0 + (tm.tv_usec - start_time.tv_usec) / 1000.0;
  149. if ((debug_level > 0) && (debug_level <= DEBUG_PERF)) {
  150. printf("PERF:%s %s %f ms\n", indent[debug_level - 1], str, time_ms);
  151. }
  152. #endif
  153. }
  154. #pragma GCC diagnostic pop
  155. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  156. void timeout_start(struct timeval * start) {
  157. gettimeofday(start, NULL);
  158. }
  159. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  160. int timeout_check(struct timeval start, uint32_t timeout_ms) {
  161. struct timeval tm;
  162. struct timeval diff;
  163. uint32_t ms;
  164. gettimeofday(&tm, NULL);
  165. TIMER_SUB(&tm, &start, &diff);
  166. ms = diff.tv_sec * 1000 + diff.tv_usec / 1000;
  167. if (ms >= timeout_ms) {
  168. return -1;
  169. } else {
  170. return 0;
  171. }
  172. }
  173. /* --- EOF ------------------------------------------------------------------ */