void pktfwd_test(void) { struct lgw_pkt_rx_s rxpkt[8]; /* array containing inbound packets + metadata */ struct lgw_pkt_rx_s *p; /* pointer on a RX packet */ int i, nb_pkt; nb_pkt = lgw_receive(8, rxpkt); if(nb_pkt == LGW_HAL_ERROR){ exit(EXIT_FAILURE); } if(nb_pkt > 0){ for (i=0; i < nb_pkt; ++i) { p = &rxpkt[i]; lw_log_rxpkt(p); } } }
int main(int argc, char **argv) { int i, j; /* loop and temporary variables */ struct timespec sleep_time = {0, 3000000}; /* 3 ms */ /* clock and log rotation management */ int log_rotate_interval = 3600; /* by default, rotation every hour */ int time_check = 0; /* variable used to limit the number of calls to time() function */ unsigned long pkt_in_log = 0; /* count the number of packet written in each log file */ /* configuration file related */ const char global_conf_fname[] = "global_conf.json"; /* contain global (typ. network-wide) configuration */ const char local_conf_fname[] = "local_conf.json"; /* contain node specific configuration, overwrite global parameters for parameters that are defined in both */ const char debug_conf_fname[] = "debug_conf.json"; /* if present, all other configuration files are ignored */ /* allocate memory for packet fetching and processing */ struct lgw_pkt_rx_s rxpkt[16]; /* array containing up to 16 inbound packets metadata */ struct lgw_pkt_rx_s *p; /* pointer on a RX packet */ int nb_pkt; /* local timestamp variables until we get accurate GPS time */ struct timespec fetch_time; char fetch_timestamp[30]; struct tm * x; /* parse command line options */ while ((i = getopt (argc, argv, "hr:")) != -1) { switch (i) { case 'h': usage(); return EXIT_FAILURE; break; case 'r': log_rotate_interval = atoi(optarg); if ((log_rotate_interval == 0) || (log_rotate_interval < -1)) { MSG( "ERROR: Invalid argument for -r option\n"); return EXIT_FAILURE; } break; default: MSG("ERROR: argument parsing use -h option for help\n"); usage(); return EXIT_FAILURE; } } /* configure signal handling */ sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigact.sa_handler = sig_handler; sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); /* configuration files management */ if (access(debug_conf_fname, R_OK) == 0) { /* if there is a debug conf, parse only the debug conf */ MSG("INFO: found debug configuration file %s, other configuration files will be ignored\n", debug_conf_fname); parse_SX1301_configuration(debug_conf_fname); parse_gateway_configuration(debug_conf_fname); } else if (access(global_conf_fname, R_OK) == 0) { /* if there is a global conf, parse it and then try to parse local conf */ MSG("INFO: found global configuration file %s, trying to parse it\n", global_conf_fname); parse_SX1301_configuration(global_conf_fname); parse_gateway_configuration(global_conf_fname); if (access(local_conf_fname, R_OK) == 0) { MSG("INFO: found local configuration file %s, trying to parse it\n", local_conf_fname); parse_SX1301_configuration(local_conf_fname); parse_gateway_configuration(local_conf_fname); } } else if (access(local_conf_fname, R_OK) == 0) { /* if there is only a local conf, parse it and that's all */ MSG("INFO: found local configuration file %s, trying to parse it\n", local_conf_fname); parse_SX1301_configuration(local_conf_fname); parse_gateway_configuration(local_conf_fname); } else { MSG("ERROR: failed to find any configuration file named %s, %s or %s\n", global_conf_fname, local_conf_fname, debug_conf_fname); return EXIT_FAILURE; } /* starting the concentrator */ i = lgw_start(); if (i == LGW_HAL_SUCCESS) { MSG("INFO: concentrator started, packet can now be received\n"); } else { MSG("ERROR: failed to start the concentrator\n"); return EXIT_FAILURE; } /* transform the MAC address into a string */ sprintf(lgwm_str, "%08X%08X", (uint32_t)(lgwm >> 32), (uint32_t)(lgwm & 0xFFFFFFFF)); /* opening log file and writing CSV header*/ time(&now_time); open_log(); /* main loop */ while ((quit_sig != 1) && (exit_sig != 1)) { /* fetch packets */ nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt); if (nb_pkt == LGW_HAL_ERROR) { MSG("ERROR: failed packet fetch, exiting\n"); return EXIT_FAILURE; } else if (nb_pkt == 0) { clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep_time, NULL); /* wait a short time if no packets */ } else { /* local timestamp generation until we get accurate GPS time */ clock_gettime(CLOCK_REALTIME, &fetch_time); x = gmtime(&(fetch_time.tv_sec)); sprintf(fetch_timestamp,"%04i-%02i-%02i %02i:%02i:%02i.%03liZ",(x->tm_year)+1900,(x->tm_mon)+1,x->tm_mday,x->tm_hour,x->tm_min,x->tm_sec,(fetch_time.tv_nsec)/1000000); /* ISO 8601 format */ } /* log packets */ for (i=0; i < nb_pkt; ++i) { p = &rxpkt[i]; /* writing gateway ID */ fprintf(log_file, "\"%08X%08X\",", (uint32_t)(lgwm >> 32), (uint32_t)(lgwm & 0xFFFFFFFF)); /* writing node MAC address */ fputs("\"\",", log_file); // TODO: need to parse payload /* writing UTC timestamp*/ fprintf(log_file, "\"%s\",", fetch_timestamp); // TODO: replace with GPS time when available /* writing internal clock */ fprintf(log_file, "%10u,", p->count_us); /* writing RX frequency */ fprintf(log_file, "%10u,", p->freq_hz); /* writing RF chain */ fprintf(log_file, "%u,", p->rf_chain); /* writing RX modem/IF chain */ fprintf(log_file, "%2d,", p->if_chain); /* writing status */ switch(p->status) { case STAT_CRC_OK: fputs("\"CRC_OK\" ,", log_file); break; case STAT_CRC_BAD: fputs("\"CRC_BAD\",", log_file); break; case STAT_NO_CRC: fputs("\"NO_CRC\" ,", log_file); break; case STAT_UNDEFINED:fputs("\"UNDEF\" ,", log_file); break; default: fputs("\"ERR\" ,", log_file); } /* writing payload size */ fprintf(log_file, "%3u,", p->size); /* writing modulation */ switch(p->modulation) { case MOD_LORA: fputs("\"LORA\",", log_file); break; case MOD_FSK: fputs("\"FSK\" ,", log_file); break; default: fputs("\"ERR\" ,", log_file); } /* writing bandwidth */ switch(p->bandwidth) { case BW_500KHZ: fputs("500000,", log_file); break; case BW_250KHZ: fputs("250000,", log_file); break; case BW_125KHZ: fputs("125000,", log_file); break; case BW_62K5HZ: fputs("62500 ,", log_file); break; case BW_31K2HZ: fputs("31200 ,", log_file); break; case BW_15K6HZ: fputs("15600 ,", log_file); break; case BW_7K8HZ: fputs("7800 ,", log_file); break; case BW_UNDEFINED: fputs("0 ,", log_file); break; default: fputs("-1 ,", log_file); } /* writing datarate */ if (p->modulation == MOD_LORA) { switch (p->datarate) { case DR_LORA_SF7: fputs("\"SF7\" ,", log_file); break; case DR_LORA_SF8: fputs("\"SF8\" ,", log_file); break; case DR_LORA_SF9: fputs("\"SF9\" ,", log_file); break; case DR_LORA_SF10: fputs("\"SF10\" ,", log_file); break; case DR_LORA_SF11: fputs("\"SF11\" ,", log_file); break; case DR_LORA_SF12: fputs("\"SF12\" ,", log_file); break; default: fputs("\"ERR\" ,", log_file); } } else if (p->modulation == MOD_FSK) { fprintf(log_file, "\"%6u\",", p->datarate); } else { fputs("\"ERR\" ,", log_file); } /* writing coderate */ switch (p->coderate) { case CR_LORA_4_5: fputs("\"4/5\",", log_file); break; case CR_LORA_4_6: fputs("\"2/3\",", log_file); break; case CR_LORA_4_7: fputs("\"4/7\",", log_file); break; case CR_LORA_4_8: fputs("\"1/2\",", log_file); break; case CR_UNDEFINED: fputs("\"\" ,", log_file); break; default: fputs("\"ERR\",", log_file); } /* writing packet RSSI */ fprintf(log_file, "%+.0f,", p->rssi); /* writing packet average SNR */ fprintf(log_file, "%+5.1f,", p->snr); /* writing hex-encoded payload (bundled in 32-bit words) */ fputs("\"", log_file); for (j = 0; j < p->size; ++j) { if ((j > 0) && (j%4 == 0)) fputs("-", log_file); fprintf(log_file, "%02X", p->payload[j]); } /* end of log file line */ fputs("\"\n", log_file); fflush(log_file); ++pkt_in_log; } /* check time and rotate log file if necessary */ ++time_check; if (time_check >= 8) { time_check = 0; time(&now_time); if (difftime(now_time, log_start_time) > log_rotate_interval) { fclose(log_file); MSG("INFO: log file %s closed, %lu packet(s) recorded\n", log_file_name, pkt_in_log); pkt_in_log = 0; open_log(); } } } if (exit_sig == 1) { /* clean up before leaving */ i = lgw_stop(); if (i == LGW_HAL_SUCCESS) { MSG("INFO: concentrator stopped successfully\n"); } else { MSG("WARNING: failed to stop concentrator successfully\n"); } fclose(log_file); MSG("INFO: log file %s closed, %lu packet(s) recorded\n", log_file_name, pkt_in_log); } MSG("INFO: Exiting packet logger program\n"); return EXIT_SUCCESS; }
int main() { struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ struct lgw_conf_rxrf_s rfconf; struct lgw_conf_rxif_s ifconf; struct lgw_pkt_rx_s rxpkt[4]; /* array containing up to 4 inbound packets metadata */ struct lgw_pkt_tx_s txpkt; /* configuration and metadata for an outbound packet */ struct lgw_pkt_rx_s *p; /* pointer on a RX packet */ int i, j; int nb_pkt; uint32_t tx_cnt = 0; unsigned long loop_cnt = 0; uint8_t status_var = 0; /* configure signal handling */ sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigact.sa_handler = sig_handler; sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); /* beginning of LoRa concentrator-specific code */ printf("Beginning of test for loragw_hal.c\n"); printf("*** Library version information ***\n%s\n\n", lgw_version_info()); /* set configuration for RF chains */ memset(&rfconf, 0, sizeof(rfconf)); rfconf.enable = true; rfconf.freq_hz = F_RX_0; lgw_rxrf_setconf(0, rfconf); /* radio A, f0 */ rfconf.enable = true; rfconf.freq_hz = F_RX_1; lgw_rxrf_setconf(1, rfconf); /* radio B, f1 */ /* set configuration for LoRa multi-SF channels (bandwidth cannot be set) */ memset(&ifconf, 0, sizeof(ifconf)); ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = -300000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(0, ifconf); /* chain 0: LoRa 125kHz, all SF, on f0 - 0.3 MHz */ ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = 300000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(1, ifconf); /* chain 1: LoRa 125kHz, all SF, on f0 + 0.3 MHz */ ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = -300000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(2, ifconf); /* chain 2: LoRa 125kHz, all SF, on f1 - 0.3 MHz */ ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = 300000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(3, ifconf); /* chain 3: LoRa 125kHz, all SF, on f1 + 0.3 MHz */ #if (LGW_MULTI_NB >= 8) ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = -100000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(4, ifconf); /* chain 4: LoRa 125kHz, all SF, on f0 - 0.1 MHz */ ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = 100000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(5, ifconf); /* chain 5: LoRa 125kHz, all SF, on f0 + 0.1 MHz */ ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = -100000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(6, ifconf); /* chain 6: LoRa 125kHz, all SF, on f1 - 0.1 MHz */ ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = 100000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(7, ifconf); /* chain 7: LoRa 125kHz, all SF, on f1 + 0.1 MHz */ #endif /* set configuration for LoRa 'stand alone' channel */ memset(&ifconf, 0, sizeof(ifconf)); ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = 0; ifconf.bandwidth = BW_250KHZ; ifconf.datarate = DR_LORA_SF10; lgw_rxif_setconf(8, ifconf); /* chain 8: LoRa 250kHz, SF10, on f0 MHz */ /* set configuration for FSK channel */ memset(&ifconf, 0, sizeof(ifconf)); ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = 0; ifconf.bandwidth = BW_250KHZ; ifconf.datarate = 64000; lgw_rxif_setconf(9, ifconf); /* chain 9: FSK 64kbps, on f1 MHz */ /* set configuration for TX packet */ memset(&txpkt, 0, sizeof(txpkt)); txpkt.freq_hz = F_TX; txpkt.tx_mode = IMMEDIATE; txpkt.rf_power = 10; txpkt.modulation = MOD_LORA; txpkt.bandwidth = BW_250KHZ; txpkt.datarate = DR_LORA_SF10; txpkt.coderate = CR_LORA_4_5; strcpy((char *)txpkt.payload, "TX.TEST.LORA.GW.????" ); txpkt.size = 20; txpkt.preamble = 6; txpkt.rf_chain = 0; /* memset(&txpkt, 0, sizeof(txpkt)); txpkt.freq_hz = F_TX; txpkt.tx_mode = IMMEDIATE; txpkt.rf_power = 10; txpkt.modulation = MOD_FSK; txpkt.f_dev = 50; txpkt.datarate = 64000; strcpy((char *)txpkt.payload, "TX.TEST.LORA.GW.????" ); txpkt.size = 20; txpkt.preamble = 4; txpkt.rf_chain = 0; */ /* connect, configure and start the LoRa concentrator */ i = lgw_start(); if (i == LGW_HAL_SUCCESS) { printf("*** Concentrator started ***\n"); } else { printf("*** Impossible to start concentrator ***\n"); return -1; } /* once configured, dump content of registers to a file, for reference */ // FILE * reg_dump = NULL; // reg_dump = fopen("reg_dump.log", "w"); // if (reg_dump != NULL) { // lgw_reg_check(reg_dump); // fclose(reg_dump); // } while ((quit_sig != 1) && (exit_sig != 1)) { loop_cnt++; /* fetch N packets */ nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt); if (nb_pkt == 0) { wait_ms(300); } else { /* display received packets */ for(i=0; i < nb_pkt; ++i) { p = &rxpkt[i]; printf("---\nRcv pkt #%d >>", i+1); if (p->status == STAT_CRC_OK) { printf(" if_chain:%2d", p->if_chain); printf(" tstamp:%010u", p->count_us); printf(" size:%3u", p->size); switch (p-> modulation) { case MOD_LORA: printf(" LoRa"); break; case MOD_FSK: printf(" FSK"); break; default: printf(" modulation?"); } switch (p->datarate) { case DR_LORA_SF7: printf(" SF7"); break; case DR_LORA_SF8: printf(" SF8"); break; case DR_LORA_SF9: printf(" SF9"); break; case DR_LORA_SF10: printf(" SF10"); break; case DR_LORA_SF11: printf(" SF11"); break; case DR_LORA_SF12: printf(" SF12"); break; default: printf(" datarate?"); } switch (p->coderate) { case CR_LORA_4_5: printf(" CR1(4/5)"); break; case CR_LORA_4_6: printf(" CR2(2/3)"); break; case CR_LORA_4_7: printf(" CR3(4/7)"); break; case CR_LORA_4_8: printf(" CR4(1/2)"); break; default: printf(" coderate?"); } printf("\n"); printf(" RSSI:%+6.1f SNR:%+5.1f (min:%+5.1f, max:%+5.1f) payload:\n", p->rssi, p->snr, p->snr_min, p->snr_max); for (j = 0; j < p->size; ++j) { printf(" %02X", p->payload[j]); } printf(" #\n"); } else if (p->status == STAT_CRC_BAD) { printf(" if_chain:%2d", p->if_chain); printf(" tstamp:%010u", p->count_us); printf(" size:%3u\n", p->size); printf(" CRC error, damaged packet\n\n"); } else if (p->status == STAT_NO_CRC){ printf(" if_chain:%2d", p->if_chain); printf(" tstamp:%010u", p->count_us); printf(" size:%3u\n", p->size); printf(" no CRC\n\n"); } else { printf(" if_chain:%2d", p->if_chain); printf(" tstamp:%010u", p->count_us); printf(" size:%3u\n", p->size); printf(" invalid status ?!?\n\n"); } } } /* send a packet every X loop */ if (loop_cnt%16 == 0) { /* 32b counter in the payload, big endian */ txpkt.payload[16] = 0xff & (tx_cnt >> 24); txpkt.payload[17] = 0xff & (tx_cnt >> 16); txpkt.payload[18] = 0xff & (tx_cnt >> 8); txpkt.payload[19] = 0xff & tx_cnt; i = lgw_send(txpkt); /* non-blocking scheduling of TX packet */ j = 0; printf("+++\nSending packet #%d, rf path %d, return %d\nstatus -> ", tx_cnt, txpkt.rf_chain, i); do { ++j; wait_ms(100); lgw_status(TX_STATUS, &status_var); /* get TX status */ printf("%d:", status_var); } while ((status_var != TX_FREE) && (j < 100)); ++tx_cnt; printf("\nTX finished\n"); } }
int main(int argc, char **argv) { struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ struct lgw_conf_board_s boardconf; struct lgw_conf_rxrf_s rfconf; struct lgw_conf_rxif_s ifconf; struct lgw_pkt_rx_s rxpkt[4]; /* array containing up to 4 inbound packets metadata */ struct lgw_pkt_tx_s txpkt; /* configuration and metadata for an outbound packet */ struct lgw_pkt_rx_s *p; /* pointer on a RX packet */ int i, j; int nb_pkt; uint32_t fa = 0, fb = 0, ft = 0; enum lgw_radio_type_e radio_type = LGW_RADIO_TYPE_NONE; uint8_t clocksource = 0; /* Radio A is source in MTAC-LORA */ uint32_t tx_cnt = 0; unsigned long loop_cnt = 0; uint8_t status_var = 0; double xd = 0.0; int xi = 0; /* parse command line options */ while ((i = getopt (argc, argv, "ha:b:t:r:k:")) != -1) { switch (i) { case 'h': usage(); return -1; break; case 'a': /* <float> Radio A RX frequency in MHz */ sscanf(optarg, "%lf", &xd); fa = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ break; case 'b': /* <float> Radio B RX frequency in MHz */ sscanf(optarg, "%lf", &xd); fb = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ break; case 't': /* <float> Radio TX frequency in MHz */ sscanf(optarg, "%lf", &xd); ft = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ break; case 'r': /* <int> Radio type (1255, 1257) */ sscanf(optarg, "%i", &xi); switch (xi) { case 1255: radio_type = LGW_RADIO_TYPE_SX1255; break; case 1257: radio_type = LGW_RADIO_TYPE_SX1257; break; default: printf("ERROR: invalid radio type\n"); usage(); return -1; } break; case 'k': /* <int> Concentrator clock source (Radio A or Radio B) */ sscanf(optarg, "%i", &xi); clocksource = (uint8_t)xi; break; default: printf("ERROR: argument parsing\n"); usage(); return -1; } } /* check input parameters */ if ((fa == 0) || (fb == 0) || (ft == 0)) { printf("ERROR: missing frequency input parameter:\n"); printf(" Radio A RX: %u\n", fa); printf(" Radio B RX: %u\n", fb); printf(" Radio TX: %u\n", ft); usage(); return -1; } if (radio_type == LGW_RADIO_TYPE_NONE) { printf("ERROR: missing radio type parameter:\n"); usage(); return -1; } /* configure signal handling */ sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigact.sa_handler = sig_handler; sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); /* beginning of LoRa concentrator-specific code */ printf("Beginning of test for loragw_hal.c\n"); printf("*** Library version information ***\n%s\n\n", lgw_version_info()); /* set configuration for board */ memset(&boardconf, 0, sizeof(boardconf)); boardconf.lorawan_public = true; boardconf.clksrc = clocksource; lgw_board_setconf(boardconf); /* set configuration for RF chains */ memset(&rfconf, 0, sizeof(rfconf)); rfconf.enable = true; rfconf.freq_hz = fa; rfconf.rssi_offset = DEFAULT_RSSI_OFFSET; rfconf.type = radio_type; rfconf.tx_enable = true; lgw_rxrf_setconf(0, rfconf); /* radio A, f0 */ rfconf.enable = true; rfconf.freq_hz = fb; rfconf.rssi_offset = DEFAULT_RSSI_OFFSET; rfconf.type = radio_type; rfconf.tx_enable = false; lgw_rxrf_setconf(1, rfconf); /* radio B, f1 */ /* set configuration for LoRa multi-SF channels (bandwidth cannot be set) */ memset(&ifconf, 0, sizeof(ifconf)); ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = -300000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(0, ifconf); /* chain 0: LoRa 125kHz, all SF, on f0 - 0.3 MHz */ ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = 300000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(1, ifconf); /* chain 1: LoRa 125kHz, all SF, on f0 + 0.3 MHz */ ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = -300000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(2, ifconf); /* chain 2: LoRa 125kHz, all SF, on f1 - 0.3 MHz */ ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = 300000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(3, ifconf); /* chain 3: LoRa 125kHz, all SF, on f1 + 0.3 MHz */ ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = -100000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(4, ifconf); /* chain 4: LoRa 125kHz, all SF, on f0 - 0.1 MHz */ ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = 100000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(5, ifconf); /* chain 5: LoRa 125kHz, all SF, on f0 + 0.1 MHz */ ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = -100000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(6, ifconf); /* chain 6: LoRa 125kHz, all SF, on f1 - 0.1 MHz */ ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = 100000; ifconf.datarate = DR_LORA_MULTI; lgw_rxif_setconf(7, ifconf); /* chain 7: LoRa 125kHz, all SF, on f1 + 0.1 MHz */ /* set configuration for LoRa 'stand alone' channel */ memset(&ifconf, 0, sizeof(ifconf)); ifconf.enable = true; ifconf.rf_chain = 0; ifconf.freq_hz = 0; ifconf.bandwidth = BW_250KHZ; ifconf.datarate = DR_LORA_SF10; lgw_rxif_setconf(8, ifconf); /* chain 8: LoRa 250kHz, SF10, on f0 MHz */ /* set configuration for FSK channel */ memset(&ifconf, 0, sizeof(ifconf)); ifconf.enable = true; ifconf.rf_chain = 1; ifconf.freq_hz = 0; ifconf.bandwidth = BW_250KHZ; ifconf.datarate = 64000; lgw_rxif_setconf(9, ifconf); /* chain 9: FSK 64kbps, on f1 MHz */ /* set configuration for TX packet */ memset(&txpkt, 0, sizeof(txpkt)); txpkt.freq_hz = ft; txpkt.tx_mode = IMMEDIATE; txpkt.rf_power = 10; txpkt.modulation = MOD_LORA; txpkt.bandwidth = BW_250KHZ; txpkt.datarate = DR_LORA_SF10; txpkt.coderate = CR_LORA_4_5; strcpy((char *)txpkt.payload, "TX.TEST.LORA.GW.????" ); txpkt.size = 20; txpkt.preamble = 6; txpkt.rf_chain = 0; /* memset(&txpkt, 0, sizeof(txpkt)); txpkt.freq_hz = F_TX; txpkt.tx_mode = IMMEDIATE; txpkt.rf_power = 10; txpkt.modulation = MOD_FSK; txpkt.f_dev = 50; txpkt.datarate = 64000; strcpy((char *)txpkt.payload, "TX.TEST.LORA.GW.????" ); txpkt.size = 20; txpkt.preamble = 4; txpkt.rf_chain = 0; */ /* connect, configure and start the LoRa concentrator */ i = lgw_start(); if (i == LGW_HAL_SUCCESS) { printf("*** Concentrator started ***\n"); } else { printf("*** Impossible to start concentrator ***\n"); return -1; } /* once configured, dump content of registers to a file, for reference */ // FILE * reg_dump = NULL; // reg_dump = fopen("reg_dump.log", "w"); // if (reg_dump != NULL) { // lgw_reg_check(reg_dump); // fclose(reg_dump); // } while ((quit_sig != 1) && (exit_sig != 1)) { loop_cnt++; /* fetch N packets */ nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt); if (nb_pkt == 0) { wait_ms(300); } else { /* display received packets */ for(i=0; i < nb_pkt; ++i) { p = &rxpkt[i]; printf("---\nRcv pkt #%d >>", i+1); if (p->status == STAT_CRC_OK) { printf(" if_chain:%2d", p->if_chain); printf(" tstamp:%010u", p->count_us); printf(" size:%3u", p->size); switch (p-> modulation) { case MOD_LORA: printf(" LoRa"); break; case MOD_FSK: printf(" FSK"); break; default: printf(" modulation?"); } switch (p->datarate) { case DR_LORA_SF7: printf(" SF7"); break; case DR_LORA_SF8: printf(" SF8"); break; case DR_LORA_SF9: printf(" SF9"); break; case DR_LORA_SF10: printf(" SF10"); break; case DR_LORA_SF11: printf(" SF11"); break; case DR_LORA_SF12: printf(" SF12"); break; default: printf(" datarate?"); } switch (p->coderate) { case CR_LORA_4_5: printf(" CR1(4/5)"); break; case CR_LORA_4_6: printf(" CR2(2/3)"); break; case CR_LORA_4_7: printf(" CR3(4/7)"); break; case CR_LORA_4_8: printf(" CR4(1/2)"); break; default: printf(" coderate?"); } printf("\n"); printf(" RSSI:%+6.1f SNR:%+5.1f (min:%+5.1f, max:%+5.1f) payload:\n", p->rssi, p->snr, p->snr_min, p->snr_max); for (j = 0; j < p->size; ++j) { printf(" %02X", p->payload[j]); } printf(" #\n"); } else if (p->status == STAT_CRC_BAD) { printf(" if_chain:%2d", p->if_chain); printf(" tstamp:%010u", p->count_us); printf(" size:%3u\n", p->size); printf(" CRC error, damaged packet\n\n"); } else if (p->status == STAT_NO_CRC){ printf(" if_chain:%2d", p->if_chain); printf(" tstamp:%010u", p->count_us); printf(" size:%3u\n", p->size); printf(" no CRC\n\n"); } else { printf(" if_chain:%2d", p->if_chain); printf(" tstamp:%010u", p->count_us); printf(" size:%3u\n", p->size); printf(" invalid status ?!?\n\n"); } } } /* send a packet every X loop */ if (loop_cnt%16 == 0) { /* 32b counter in the payload, big endian */ txpkt.payload[16] = 0xff & (tx_cnt >> 24); txpkt.payload[17] = 0xff & (tx_cnt >> 16); txpkt.payload[18] = 0xff & (tx_cnt >> 8); txpkt.payload[19] = 0xff & tx_cnt; i = lgw_send(txpkt); /* non-blocking scheduling of TX packet */ j = 0; printf("+++\nSending packet #%d, rf path %d, return %d\nstatus -> ", tx_cnt, txpkt.rf_chain, i); do { ++j; wait_ms(100); lgw_status(TX_STATUS, &status_var); /* get TX status */ printf("%d:", status_var); } while ((status_var != TX_FREE) && (j < 100)); ++tx_cnt; printf("\nTX finished\n"); } }
int main(int argc, char **argv) { int i; /* loop and temporary variables */ struct timespec sleep_time = {0, 3000000}; /* 3 ms */ int packet_counter = 0; /* allocate memory for packet fetching and processing */ struct lgw_pkt_rx_s rxpkt[16]; /* array containing up to 16 inbound packets metadata */ struct lgw_pkt_rx_s *p; /* pointer on a RX packet */ int nb_pkt; configure_gateway(); /* parse command line options */ while ((i = getopt (argc, argv, "hr:")) != -1) { switch (i) { case 'h': usage(); return EXIT_FAILURE; break; case 'r': result_file_name = optarg; break; default: MSG("ERROR: argument parsing use -h option for help\n"); usage(); return EXIT_FAILURE; } } /* configure signal handling */ sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigact.sa_handler = sig_handler; sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); /* starting the concentrator */ i = lgw_start(); if (i == LGW_HAL_SUCCESS) { MSG("INFO: concentrator started, packet can now be received\n"); } else { MSG("ERROR: failed to start the concentrator\n"); return EXIT_FAILURE; } openResultFile(); /* transform the MAC address into a string */ sprintf(lgwm_str, "%08X%08X", (uint32_t)(lgwm >> 32), (uint32_t)(lgwm & 0xFFFFFFFF)); /* main loop */ while ((quit_sig != 1) && (exit_sig != 1)) { /* fetch packets */ nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt); if (nb_pkt == LGW_HAL_ERROR) { MSG("ERROR: failed packet fetch, exiting\n"); return EXIT_FAILURE; } else if (nb_pkt == 0) { clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep_time, NULL); /* wait a short time if no packets */ } else { /* local timestamp generation until we get accurate GPS time */ } /* log packets */ for (i=0; i < nb_pkt; ++i) { p = &rxpkt[i]; switch(compare_id(p)) { case JOIN_REQ_MSG: MSG("Sending join response.\n"); send_join_response(p); packet_counter = 0; size = 0; break; case TEST_MSG: snr[packet_counter] = p->snr; packet_counter++; size = p->size; break; case END_TEST_MSG: if (packet_counter != 0) { write_results(packet_counter, p); MSG("Ended series: %i packets received.\n", packet_counter); } packet_counter = 0; size = 0; break; case ALL_TESTS_ENDED_MSG: exit_sig = 1; // ending program MSG("All tests have been finished.\n"); break; default: // message not recognized break; } } } if (exit_sig == 1) { /* clean up before leaving */ i = lgw_stop(); if (i == LGW_HAL_SUCCESS) { MSG("INFO: concentrator stopped successfully\n"); } else { MSG("WARNING: failed to stop concentrator successfully\n"); } } fclose(result_file); MSG("INFO: Exiting uplink concentrator program\n"); return EXIT_SUCCESS; }