test_loragw_hal_tx.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. /*
  2. / _____) _ | |
  3. ( (____ _____ ____ _| |_ _____ ____| |__
  4. \____ \| ___ | (_ _) ___ |/ ___) _ \
  5. _____) ) ____| | | || |_| ____( (___| | | |
  6. (______/|_____)_|_|_| \__)_____)\____)_| |_|
  7. (C)2019 Semtech
  8. Description:
  9. Minimum test program for HAL TX capability
  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 <stdint.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <unistd.h>
  25. #include <math.h>
  26. #include <signal.h> /* sigaction */
  27. #include <getopt.h> /* getopt_long */
  28. #include "loragw_hal.h"
  29. #include "loragw_reg.h"
  30. #include "loragw_aux.h"
  31. /* -------------------------------------------------------------------------- */
  32. /* --- PRIVATE MACROS ------------------------------------------------------- */
  33. #define RAND_RANGE(min, max) (rand() % (max + 1 - min) + min)
  34. /* -------------------------------------------------------------------------- */
  35. /* --- PRIVATE CONSTANTS ---------------------------------------------------- */
  36. #define COM_TYPE_DEFAULT LGW_COM_SPI
  37. #define COM_PATH_DEFAULT "/dev/spidev0.0"
  38. #define DEFAULT_CLK_SRC 0
  39. #define DEFAULT_FREQ_HZ 868500000U
  40. /* -------------------------------------------------------------------------- */
  41. /* --- PRIVATE VARIABLES ---------------------------------------------------- */
  42. /* Signal handling variables */
  43. static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
  44. static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
  45. /* -------------------------------------------------------------------------- */
  46. /* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
  47. /* describe command line options */
  48. void usage(void) {
  49. //printf("Library version information: %s\n", lgw_version_info());
  50. printf("Available options:\n");
  51. printf(" -h print this help\n");
  52. printf(" -u Set COM type as USB (default is SPI)\n");
  53. printf(" -d <path> COM path to be used to connect the concentrator\n");
  54. printf(" => default path: " COM_PATH_DEFAULT "\n");
  55. printf(" -k <uint> Concentrator clock source (Radio A or Radio B) [0..1]\n");
  56. printf(" -c <uint> RF chain to be used for TX (Radio A or Radio B) [0..1]\n");
  57. printf(" -r <uint> Radio type (1255, 1257, 1250)\n");
  58. printf(" -f <float> Radio TX frequency in MHz\n");
  59. printf(" -m <str> modulation type ['CW', 'LORA', 'FSK']\n");
  60. printf(" -o <int> CW frequency offset from Radio TX frequency in kHz [-65..65]\n");
  61. printf(" -s <uint> LoRa datarate 0:random, [5..12]\n");
  62. printf(" -b <uint> LoRa bandwidth in khz 0:random, [125, 250, 500]\n");
  63. printf(" -l <uint> FSK/LoRa preamble length, [6..65535]\n");
  64. printf(" -n <uint> Number of packets to be sent\n");
  65. printf(" -z <uint> size of packets to be sent 0:random, [9..255]\n");
  66. printf(" -t <uint> TX mode timestamped with delay in ms. If delay is 0, TX mode GPS trigger\n");
  67. printf(" -p <int> RF power in dBm\n");
  68. printf(" -i Send LoRa packet using inverted modulation polarity\n");
  69. printf(" -j Set radio in single input mode (SX1250 only)\n");
  70. printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
  71. printf(" --fdev <uint> FSK frequency deviation in kHz [1:250]\n");
  72. printf(" --br <float> FSK bitrate in kbps [0.5:250]\n");
  73. printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
  74. printf(" --pa <uint> PA gain SX125x:[0..3], SX1250:[0,1]\n");
  75. printf(" --dig <uint> sx1302 digital gain for sx125x [0..3]\n");
  76. printf(" --dac <uint> sx125x DAC gain [0..3]\n");
  77. printf(" --mix <uint> sx125x MIX gain [5..15]\n");
  78. printf(" --pwid <uint> sx1250 power index [0..22]\n");
  79. printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
  80. printf(" --nhdr Send LoRa packet with implicit header\n");
  81. printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
  82. printf(" --loop Number of loops for HAL start/stop (HAL unitary test)\n");
  83. printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
  84. printf(" --fdd Enable Full-Duplex mode (CN490 reference design)\n");
  85. }
  86. /* handle signals */
  87. static void sig_handler(int sigio)
  88. {
  89. if (sigio == SIGQUIT) {
  90. quit_sig = 1;
  91. }
  92. else if((sigio == SIGINT) || (sigio == SIGTERM)) {
  93. exit_sig = 1;
  94. }
  95. }
  96. /* -------------------------------------------------------------------------- */
  97. /* --- MAIN FUNCTION -------------------------------------------------------- */
  98. int main(int argc, char **argv)
  99. {
  100. int i, x;
  101. uint32_t ft = DEFAULT_FREQ_HZ;
  102. int8_t rf_power = 0;
  103. uint8_t sf = 0;
  104. uint16_t bw_khz = 0;
  105. uint32_t nb_pkt = 1;
  106. unsigned int nb_loop = 1, cnt_loop;
  107. uint8_t size = 0;
  108. char mod[64] = "LORA";
  109. float br_kbps = 50;
  110. uint8_t fdev_khz = 25;
  111. int8_t freq_offset = 0;
  112. double arg_d = 0.0;
  113. unsigned int arg_u;
  114. int arg_i;
  115. char arg_s[64];
  116. float xf = 0.0;
  117. uint8_t clocksource = 0;
  118. uint8_t rf_chain = 0;
  119. lgw_radio_type_t radio_type = LGW_RADIO_TYPE_SX1250;
  120. uint16_t preamble = 8;
  121. bool invert_pol = false;
  122. bool no_header = false;
  123. bool single_input_mode = false;
  124. bool full_duplex = false;
  125. struct lgw_conf_board_s boardconf;
  126. struct lgw_conf_rxrf_s rfconf;
  127. struct lgw_pkt_tx_s pkt;
  128. struct lgw_tx_gain_lut_s txlut; /* TX gain table */
  129. uint8_t tx_status;
  130. uint32_t count_us;
  131. uint32_t trig_delay_us = 1000000;
  132. bool trig_delay = false;
  133. /* SPI interfaces */
  134. const char com_path_default[] = COM_PATH_DEFAULT;
  135. const char * com_path = com_path_default;
  136. lgw_com_type_t com_type = COM_TYPE_DEFAULT;
  137. static struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
  138. /* Initialize TX gain LUT */
  139. txlut.size = 0;
  140. memset(txlut.lut, 0, sizeof txlut.lut);
  141. /* Parameter parsing */
  142. int option_index = 0;
  143. static struct option long_options[] = {
  144. {"fdev", required_argument, 0, 0},
  145. {"br", required_argument, 0, 0},
  146. {"pa", required_argument, 0, 0},
  147. {"dac", required_argument, 0, 0},
  148. {"dig", required_argument, 0, 0},
  149. {"mix", required_argument, 0, 0},
  150. {"pwid", required_argument, 0, 0},
  151. {"loop", required_argument, 0, 0},
  152. {"nhdr", no_argument, 0, 0},
  153. {"fdd", no_argument, 0, 0},
  154. {0, 0, 0, 0}
  155. };
  156. /* parse command line options */
  157. while ((i = getopt_long (argc, argv, "hjif:s:b:n:z:p:k:r:c:l:t:m:o:ud:", long_options, &option_index)) != -1) {
  158. switch (i) {
  159. case 'h':
  160. usage();
  161. return -1;
  162. break;
  163. case 'u':
  164. com_type = LGW_COM_USB;
  165. break;
  166. case 'd': /* <char> COM path */
  167. if (optarg != NULL) {
  168. com_path = optarg;
  169. }
  170. break;
  171. case 'i': /* Send packet using inverted modulation polarity */
  172. invert_pol = true;
  173. break;
  174. case 'j': /* Set radio in single input mode */
  175. single_input_mode = true;
  176. break;
  177. case 'r': /* <uint> Radio type */
  178. i = sscanf(optarg, "%u", &arg_u);
  179. if ((i != 1) || ((arg_u != 1255) && (arg_u != 1257) && (arg_u != 1250))) {
  180. printf("ERROR: argument parsing of -r argument. Use -h to print help\n");
  181. return EXIT_FAILURE;
  182. } else {
  183. switch (arg_u) {
  184. case 1255:
  185. radio_type = LGW_RADIO_TYPE_SX1255;
  186. break;
  187. case 1257:
  188. radio_type = LGW_RADIO_TYPE_SX1257;
  189. break;
  190. default: /* 1250 */
  191. radio_type = LGW_RADIO_TYPE_SX1250;
  192. break;
  193. }
  194. }
  195. break;
  196. case 'l': /* <uint> LoRa/FSK preamble length */
  197. i = sscanf(optarg, "%u", &arg_u);
  198. if ((i != 1) || (arg_u > 65535)) {
  199. printf("ERROR: argument parsing of -l argument. Use -h to print help\n");
  200. return EXIT_FAILURE;
  201. } else {
  202. preamble = (uint16_t)arg_u;
  203. }
  204. break;
  205. case 'm': /* <str> Modulation type */
  206. i = sscanf(optarg, "%s", arg_s);
  207. if ((i != 1) || ((strcmp(arg_s, "CW") != 0) && (strcmp(arg_s, "LORA") != 0) && (strcmp(arg_s, "FSK")))) {
  208. printf("ERROR: invalid modulation type\n");
  209. return EXIT_FAILURE;
  210. } else {
  211. sprintf(mod, "%s", arg_s);
  212. }
  213. break;
  214. case 'o': /* <int> CW frequency offset from Radio TX frequency */
  215. i = sscanf(optarg, "%d", &arg_i);
  216. if ((arg_i < -65) || (arg_i > 65)) {
  217. printf("ERROR: invalid frequency offset\n");
  218. return EXIT_FAILURE;
  219. } else {
  220. freq_offset = (int32_t)arg_i;
  221. }
  222. break;
  223. case 't': /* <uint> Trigger delay in ms */
  224. i = sscanf(optarg, "%u", &arg_u);
  225. if (i != 1) {
  226. printf("ERROR: argument parsing of -t argument. Use -h to print help\n");
  227. return EXIT_FAILURE;
  228. } else {
  229. trig_delay = true;
  230. trig_delay_us = (uint32_t)(arg_u * 1E3);
  231. }
  232. break;
  233. case 'k': /* <uint> Clock Source */
  234. i = sscanf(optarg, "%u", &arg_u);
  235. if ((i != 1) || (arg_u > 1)) {
  236. printf("ERROR: argument parsing of -k argument. Use -h to print help\n");
  237. return EXIT_FAILURE;
  238. } else {
  239. clocksource = (uint8_t)arg_u;
  240. }
  241. break;
  242. case 'c': /* <uint> RF chain */
  243. i = sscanf(optarg, "%u", &arg_u);
  244. if ((i != 1) || (arg_u > 1)) {
  245. printf("ERROR: argument parsing of -c argument. Use -h to print help\n");
  246. return EXIT_FAILURE;
  247. } else {
  248. rf_chain = (uint8_t)arg_u;
  249. }
  250. break;
  251. case 'f': /* <float> Radio TX frequency in MHz */
  252. i = sscanf(optarg, "%lf", &arg_d);
  253. if (i != 1) {
  254. printf("ERROR: argument parsing of -f argument. Use -h to print help\n");
  255. return EXIT_FAILURE;
  256. } else {
  257. ft = (uint32_t)((arg_d*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
  258. }
  259. break;
  260. case 's': /* <uint> LoRa datarate */
  261. i = sscanf(optarg, "%u", &arg_u);
  262. if ((i != 1) || (arg_u < 5) || (arg_u > 12)) {
  263. printf("ERROR: argument parsing of -s argument. Use -h to print help\n");
  264. return EXIT_FAILURE;
  265. } else {
  266. sf = (uint8_t)arg_u;
  267. }
  268. break;
  269. case 'b': /* <uint> LoRa bandwidth in khz */
  270. i = sscanf(optarg, "%u", &arg_u);
  271. if ((i != 1) || ((arg_u != 125) && (arg_u != 250) && (arg_u != 500))) {
  272. printf("ERROR: argument parsing of -b argument. Use -h to print help\n");
  273. return EXIT_FAILURE;
  274. } else {
  275. bw_khz = (uint16_t)arg_u;
  276. }
  277. break;
  278. case 'n': /* <uint> Number of packets to be sent */
  279. i = sscanf(optarg, "%u", &arg_u);
  280. if (i != 1) {
  281. printf("ERROR: argument parsing of -n argument. Use -h to print help\n");
  282. return EXIT_FAILURE;
  283. } else {
  284. nb_pkt = (uint32_t)arg_u;
  285. }
  286. break;
  287. case 'p': /* <int> RF power */
  288. i = sscanf(optarg, "%d", &arg_i);
  289. if (i != 1) {
  290. printf("ERROR: argument parsing of -p argument. Use -h to print help\n");
  291. return EXIT_FAILURE;
  292. } else {
  293. rf_power = (int8_t)arg_i;
  294. txlut.size = 1;
  295. txlut.lut[0].rf_power = rf_power;
  296. }
  297. break;
  298. case 'z': /* <uint> packet size */
  299. i = sscanf(optarg, "%u", &arg_u);
  300. if ((i != 1) || (arg_u < 9) || (arg_u > 255)) {
  301. printf("ERROR: argument parsing of -z argument. Use -h to print help\n");
  302. return EXIT_FAILURE;
  303. } else {
  304. size = (uint8_t)arg_u;
  305. }
  306. break;
  307. case 0:
  308. if (strcmp(long_options[option_index].name, "fdev") == 0) {
  309. i = sscanf(optarg, "%u", &arg_u);
  310. if ((i != 1) || (arg_u < 1) || (arg_u > 250)) {
  311. printf("ERROR: invalid FSK frequency deviation\n");
  312. return EXIT_FAILURE;
  313. } else {
  314. fdev_khz = (uint8_t)arg_u;
  315. }
  316. } else if (strcmp(long_options[option_index].name, "br") == 0) {
  317. i = sscanf(optarg, "%f", &xf);
  318. if ((i != 1) || (xf < 0.5) || (xf > 250)) {
  319. printf("ERROR: invalid FSK bitrate\n");
  320. return EXIT_FAILURE;
  321. } else {
  322. br_kbps = xf;
  323. }
  324. } else if (strcmp(long_options[option_index].name, "pa") == 0) {
  325. i = sscanf(optarg, "%u", &arg_u);
  326. if ((i != 1) || (arg_u > 3)) {
  327. printf("ERROR: argument parsing of --pa argument. Use -h to print help\n");
  328. return EXIT_FAILURE;
  329. } else {
  330. txlut.size = 1;
  331. txlut.lut[0].pa_gain = (uint8_t)arg_u;
  332. }
  333. } else if (strcmp(long_options[option_index].name, "dac") == 0) {
  334. i = sscanf(optarg, "%u", &arg_u);
  335. if ((i != 1) || (arg_u > 3)) {
  336. printf("ERROR: argument parsing of --dac argument. Use -h to print help\n");
  337. return EXIT_FAILURE;
  338. } else {
  339. txlut.size = 1;
  340. txlut.lut[0].dac_gain = (uint8_t)arg_u;
  341. }
  342. } else if (strcmp(long_options[option_index].name, "mix") == 0) {
  343. i = sscanf(optarg, "%u", &arg_u);
  344. if ((i != 1) || (arg_u > 15)) {
  345. printf("ERROR: argument parsing of --mix argument. Use -h to print help\n");
  346. return EXIT_FAILURE;
  347. } else {
  348. txlut.size = 1;
  349. txlut.lut[0].mix_gain = (uint8_t)arg_u;
  350. }
  351. } else if (strcmp(long_options[option_index].name, "dig") == 0) {
  352. i = sscanf(optarg, "%u", &arg_u);
  353. if ((i != 1) || (arg_u > 3)) {
  354. printf("ERROR: argument parsing of --dig argument. Use -h to print help\n");
  355. return EXIT_FAILURE;
  356. } else {
  357. txlut.size = 1;
  358. txlut.lut[0].dig_gain = (uint8_t)arg_u;
  359. }
  360. } else if (strcmp(long_options[option_index].name, "pwid") == 0) {
  361. i = sscanf(optarg, "%u", &arg_u);
  362. if ((i != 1) || (arg_u > 22)) {
  363. printf("ERROR: argument parsing of --pwid argument. Use -h to print help\n");
  364. return EXIT_FAILURE;
  365. } else {
  366. txlut.size = 1;
  367. txlut.lut[0].mix_gain = 5; /* TODO: rework this, should not be needed for sx1250 */
  368. txlut.lut[0].pwr_idx = (uint8_t)arg_u;
  369. }
  370. } else if (strcmp(long_options[option_index].name, "loop") == 0) {
  371. printf("%p\n", optarg);
  372. i = sscanf(optarg, "%u", &arg_u);
  373. if (i != 1) {
  374. printf("ERROR: argument parsing of --loop argument. Use -h to print help\n");
  375. return EXIT_FAILURE;
  376. } else {
  377. nb_loop = arg_u;
  378. }
  379. } else if (strcmp(long_options[option_index].name, "nhdr") == 0) {
  380. no_header = true;
  381. } else if (strcmp(long_options[option_index].name, "fdd") == 0) {
  382. full_duplex = true;
  383. } else {
  384. printf("ERROR: argument parsing options. Use -h to print help\n");
  385. return EXIT_FAILURE;
  386. }
  387. break;
  388. default:
  389. printf("ERROR: argument parsing\n");
  390. usage();
  391. return -1;
  392. }
  393. }
  394. /* Summary of packet parameters */
  395. if (strcmp(mod, "CW") == 0) {
  396. printf("Sending %i CW on %u Hz (Freq. offset %d kHz) at %i dBm\n", nb_pkt, ft, freq_offset, rf_power);
  397. }
  398. else if (strcmp(mod, "FSK") == 0) {
  399. printf("Sending %i FSK packets on %u Hz (FDev %u kHz, Bitrate %.2f, %i bytes payload, %i symbols preamble) at %i dBm\n", nb_pkt, ft, fdev_khz, br_kbps, size, preamble, rf_power);
  400. } else {
  401. printf("Sending %i LoRa packets on %u Hz (BW %i kHz, SF %i, CR %i, %i bytes payload, %i symbols preamble, %s header, %s polarity) at %i dBm\n", nb_pkt, ft, bw_khz, sf, 1, size, preamble, (no_header == false) ? "explicit" : "implicit", (invert_pol == false) ? "non-inverted" : "inverted", rf_power);
  402. }
  403. //处理中断推出
  404. /* Configure signal handling */
  405. sigemptyset( &sigact.sa_mask );
  406. sigact.sa_flags = 0;
  407. sigact.sa_handler = sig_handler;
  408. sigaction( SIGQUIT, &sigact, NULL );
  409. sigaction( SIGINT, &sigact, NULL );
  410. sigaction( SIGTERM, &sigact, NULL );
  411. /* Configure the gateway */
  412. memset( &boardconf, 0, sizeof boardconf);
  413. boardconf.lorawan_public = true;
  414. boardconf.clksrc = clocksource;
  415. boardconf.full_duplex = full_duplex;
  416. boardconf.com_type = com_type;
  417. strncpy(boardconf.com_path, com_path, sizeof boardconf.com_path);
  418. boardconf.com_path[sizeof boardconf.com_path - 1] = '\0'; /* ensure string termination */
  419. if (lgw_board_setconf(&boardconf) != LGW_HAL_SUCCESS) {
  420. printf("ERROR: failed to configure board\n");
  421. return EXIT_FAILURE;
  422. }
  423. memset( &rfconf, 0, sizeof rfconf);
  424. rfconf.enable = true; /* rf chain 0 needs to be enabled for calibration to work on sx1257 */
  425. rfconf.freq_hz = ft;
  426. rfconf.type = radio_type;
  427. rfconf.tx_enable = true;
  428. rfconf.single_input_mode = single_input_mode;
  429. if (lgw_rxrf_setconf(0, &rfconf) != LGW_HAL_SUCCESS) {
  430. printf("ERROR: failed to configure rxrf 0\n");
  431. return EXIT_FAILURE;
  432. }
  433. memset( &rfconf, 0, sizeof rfconf);
  434. rfconf.enable = (((rf_chain == 1) || (clocksource == 1)) ? true : false);
  435. rfconf.freq_hz = ft;
  436. rfconf.type = radio_type;
  437. rfconf.tx_enable = false;
  438. rfconf.single_input_mode = single_input_mode;
  439. if (lgw_rxrf_setconf(1, &rfconf) != LGW_HAL_SUCCESS) {
  440. printf("ERROR: failed to configure rxrf 1\n");
  441. return EXIT_FAILURE;
  442. }
  443. if (txlut.size > 0) {
  444. if (lgw_txgain_setconf(rf_chain, &txlut) != LGW_HAL_SUCCESS) {
  445. printf("ERROR: failed to configure txgain lut\n");
  446. return EXIT_FAILURE;
  447. }
  448. }
  449. for (cnt_loop = 0; cnt_loop < nb_loop; cnt_loop++) {
  450. if (com_type == LGW_COM_SPI) {
  451. /* Board reset */
  452. if (system("./reset_lgw.sh start") != 0) {
  453. printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
  454. exit(EXIT_FAILURE);
  455. }
  456. }
  457. /* connect, configure and start the LoRa concentrator */
  458. x = lgw_start();
  459. if (x != 0) {
  460. printf("ERROR: failed to start the gateway\n");
  461. return EXIT_FAILURE;
  462. }
  463. /* Send packets */
  464. memset(&pkt, 0, sizeof pkt);
  465. pkt.rf_chain = rf_chain;
  466. pkt.freq_hz = ft;
  467. pkt.rf_power = rf_power;
  468. if (trig_delay == false) {
  469. pkt.tx_mode = IMMEDIATE;
  470. } else {
  471. if (trig_delay_us == 0) {
  472. pkt.tx_mode = ON_GPS;
  473. } else {
  474. pkt.tx_mode = TIMESTAMPED;
  475. }
  476. }
  477. if ( strcmp( mod, "CW" ) == 0 ) {
  478. pkt.modulation = MOD_CW;
  479. pkt.freq_offset = freq_offset;
  480. pkt.f_dev = fdev_khz;
  481. }
  482. else if( strcmp( mod, "FSK" ) == 0 ) {
  483. pkt.modulation = MOD_FSK;
  484. pkt.no_crc = false;
  485. pkt.datarate = br_kbps * 1e3;
  486. pkt.f_dev = fdev_khz;
  487. } else {
  488. pkt.modulation = MOD_LORA;
  489. pkt.coderate = CR_LORA_4_5;
  490. pkt.no_crc = true;
  491. }
  492. pkt.invert_pol = invert_pol;
  493. pkt.preamble = preamble;
  494. pkt.no_header = no_header;
  495. pkt.payload[0] = 0x40; /* Confirmed Data Up */
  496. pkt.payload[1] = 0xAB;
  497. pkt.payload[2] = 0xAB;
  498. pkt.payload[3] = 0xAB;
  499. pkt.payload[4] = 0xAB;
  500. pkt.payload[5] = 0x00; /* FCTrl */
  501. pkt.payload[6] = 0; /* FCnt */
  502. pkt.payload[7] = 0; /* FCnt */
  503. pkt.payload[8] = 0x02; /* FPort */
  504. for (i = 9; i < 255; i++) {
  505. pkt.payload[i] = i;
  506. }
  507. for (i = 0; i < (int)nb_pkt; i++) {
  508. if (trig_delay == true) {
  509. if (trig_delay_us > 0) {
  510. lgw_get_instcnt(&count_us);
  511. printf("count_us:%u\n", count_us);
  512. pkt.count_us = count_us + trig_delay_us;
  513. printf("programming TX for %u\n", pkt.count_us);
  514. } else {
  515. printf("programming TX for next PPS (GPS)\n");
  516. }
  517. }
  518. if( strcmp( mod, "LORA" ) == 0 ) {
  519. pkt.datarate = (sf == 0) ? (uint8_t)RAND_RANGE(5, 12) : sf;
  520. }
  521. switch (bw_khz) {
  522. case 125:
  523. pkt.bandwidth = BW_125KHZ;
  524. break;
  525. case 250:
  526. pkt.bandwidth = BW_250KHZ;
  527. break;
  528. case 500:
  529. pkt.bandwidth = BW_500KHZ;
  530. break;
  531. default:
  532. pkt.bandwidth = (uint8_t)RAND_RANGE(BW_125KHZ, BW_500KHZ);
  533. break;
  534. }
  535. pkt.size = (size == 0) ? (uint8_t)RAND_RANGE(9, 255) : size;
  536. pkt.payload[6] = (uint8_t)(i >> 0); /* FCnt */
  537. pkt.payload[7] = (uint8_t)(i >> 8); /* FCnt */
  538. x = lgw_send(&pkt);
  539. if (x != 0) {
  540. printf("ERROR: failed to send packet\n");
  541. break;
  542. }
  543. /* wait for packet to finish sending */
  544. do {
  545. wait_ms(5);
  546. lgw_status(pkt.rf_chain, TX_STATUS, &tx_status); /* get TX status */
  547. } while ((tx_status != TX_FREE) && (quit_sig != 1) && (exit_sig != 1));
  548. if ((quit_sig == 1) || (exit_sig == 1)) {
  549. break;
  550. }
  551. printf("TX done\n");
  552. }
  553. printf( "\nNb packets sent: %u (%u)\n", i, cnt_loop + 1 );
  554. /* Stop the gateway */
  555. x = lgw_stop();
  556. if (x != 0) {
  557. printf("ERROR: failed to stop the gateway\n");
  558. }
  559. if (com_type == LGW_COM_SPI) {
  560. /* Board reset */
  561. if (system("./reset_lgw.sh stop") != 0) {
  562. printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
  563. exit(EXIT_FAILURE);
  564. }
  565. }
  566. }
  567. printf("=========== Test End ===========\n");
  568. return 0;
  569. }
  570. /* --- EOF ------------------------------------------------------------------ */