int main(int argc, char **argv) { int i; /* temporary variable(s) */ int32_t reg_val; /* user chosen parameters */ double f1 = 0.0; double f2 = 0.0; double fs = 0.0; /* frequency scan parameters (default values) */ uint32_t f_start = rf_rx_lowfreq_[RF_CHAIN]; /* in Hz */ uint32_t f_stop = rf_rx_upfreq_[RF_CHAIN]; /* in Hz */ uint32_t f_step = 200000; /* 200 kHz step by default */ /* RSSI measurement results */ int8_t rssi_max; /* max RSSI during X measurements */ int high_count; /* nb of measurements above a threshold defined by maximum RSSI */ /* clock, log file and log rotation management */ FILE * log_file = NULL; char log_file_name[64]; char iso_date[20]; time_t now_time; /* variables for PLL register calculation */ uint32_t f_target; /* loop variable */ uint32_t freq_hz; uint32_t part_int; uint32_t part_frac; int cpt_attempts = 0; /* parse command line options */ while ((i = getopt (argc, argv, "hf:")) != -1) { switch (i) { case 'h': usage(); return EXIT_SUCCESS; case 'f': sscanf(optarg, "%lf:%lf:%lf", &f1, &f2, &fs); /* check configuration sanity */ if (f2 < f1) { MSG("ERROR: stop frequency must be bigger than start frequency\n"); return EXIT_FAILURE; } if ((f1 < 30.0) || (f1 > 3000.0)) { MSG("ERROR: invalid start frequency %f MHz\n", f1); return EXIT_FAILURE; } if ((f2 < 30.0) || (f2 > 3000.0)) { MSG("ERROR: invalid stop frequency %f MHz\n", f2); return EXIT_FAILURE; } f_start = (uint32_t)((f1*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ f_stop = (uint32_t)((f2*1e6) + 0.5); if (fs > 0.01) { f_step = (uint32_t)((fs*1e6) + 0.5); } break; default: MSG("ERROR: argument parsing use -h option for help\n"); usage(); return EXIT_FAILURE; } } printf("Scanning from %u Hz to %u Hz with a %u Hz frequency step\n", f_start, f_stop, f_step); /* 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); /* establish connection with concentrator and reset it */ if (lgw_connect() == LGW_REG_ERROR) { MSG("ERROR: fail to connect to concentrator board\n"); return EXIT_FAILURE; } lgw_soft_reset(); /* Ungate concentrator clock, switch on the radios and reset them */ lgw_reg_w(LGW_GLOBAL_EN, 1); lgw_reg_w(LGW_RADIO_A_EN,1); lgw_reg_w(LGW_RADIO_B_EN,1); wait_ms(500); lgw_reg_w(LGW_RADIO_RST,1); wait_ms(5); lgw_reg_w(LGW_RADIO_RST,0); wait_ms(5); /* enter basic parameters for the radio */ sx125x_write_(RF_CHAIN, 0x10, SX125x_TX_DAC_CLK_SEL + SX125x_CLK_OUT*2); sx125x_write_(RF_CHAIN, 0x0C, 0 + SX125x_RX_BB_GAIN*2 + SX125x_RX_LNA_GAIN*32); /* not required, firmware should take care of that */ sx125x_write_(RF_CHAIN, 0x0D, SX125x_RXBB_BW + SX125x_RX_ADC_TRIM*4 + SX125x_RX_ADC_BW*32); /* configure the IF and concentrator parameters */ lgw_reg_w(LGW_IF_FREQ_0, -282); /* default -384 */ lgw_reg_w(LGW_IF_FREQ_1, -128); /* default -128 */ lgw_reg_w(LGW_RSSI_BB_FILTER_ALPHA,9); /* default 7 */ lgw_reg_w(LGW_RSSI_DEC_FILTER_ALPHA,7); /* default 5 */ lgw_reg_w(LGW_RSSI_CHANN_FILTER_ALPHA,3); /* default 8 */ lgw_reg_w(LGW_RSSI_CHANN_DEFAULT_VALUE,90); /* default 100 */ lgw_reg_w(LGW_RSSI_DEC_DEFAULT_VALUE,90); /* default 100 */ /* Load firmware */ load_firmware_(MCU_AGC, rssi_firmware, MCU_AGC_FW_BYTE); lgw_reg_w(LGW_FORCE_HOST_FE_CTRL,0); lgw_reg_w(LGW_FORCE_DEC_FILTER_GAIN,0); /* open log file */ time(&now_time); strftime(iso_date,ARRAY_SIZE(iso_date),"%Y%m%dT%H%M%SZ",gmtime(&now_time)); /* format yyyymmddThhmmssZ */ sprintf(log_file_name, "band_survey_%s.csv", iso_date); log_file = fopen(log_file_name, "a"); /* create log file, append if file already exist */ if (log_file == NULL) { MSG("ERROR: impossible to create log file %s\n", log_file_name); return EXIT_FAILURE; } i = fprintf(log_file, "\"Frequency (Hz)\",\"RSSI (dB)\",\"high meas (nb)\"\n"); if (i < 0) { MSG("ERROR: impossible to write to log file %s\n", log_file_name); return EXIT_FAILURE; } /* main loop */ f_target = f_start; while ((quit_sig != 1) && (exit_sig != 1) && (f_target <= f_stop)) { /* set PLL to target frequency */ freq_hz = f_target - MEAS_IF; #if (CFG_RADIO_1257 == 1) part_int = freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */ part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */ #elif (CFG_RADIO_1255 == 1) part_int = freq_hz / (SX125x_32MHz_FRAC << 7); /* integer part, gives the MSB */ part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 7)) << 9) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */ #endif sx125x_write_(RF_CHAIN, 0x01,0xFF & part_int); /* Most Significant Byte */ sx125x_write_(RF_CHAIN, 0x02,0xFF & (part_frac >> 8)); /* middle byte */ sx125x_write_(RF_CHAIN, 0x03,0xFF & part_frac); /* Least Significant Byte */ /* start and PLL lock */ cpt_attempts = 0; do { if (cpt_attempts >= PLL_LOCK_MAX_ATTEMPTS) { MSG("ERROR: fail to lock PLL\n"); return -1; } sx125x_write_(RF_CHAIN, 0x00, 1); /* enable Xtal oscillator */ sx125x_write_(RF_CHAIN, 0x00, 3); /* Enable RX (PLL+FE) */ ++cpt_attempts; wait_ms(1); } while((sx125x_read_(RF_CHAIN, 0x11) & 0x02) == 0); /* give control of the radio to the MCU and get it out of reset */ lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL,0); lgw_reg_w(LGW_MCU_RST_1, 0); /* wait for the firmware to finish running and fetch the result */ do { wait_ms(1); lgw_reg_r(LGW_MCU_AGC_STATUS, ®_val); } while (reg_val != 1); lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR,0x20); lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, ®_val); rssi_max = (int8_t)reg_val; lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR,0x21); lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, ®_val); high_count = reg_val; lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR,0x22); lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, ®_val); high_count += (reg_val << 8); /* log the measurement */ i = fprintf(log_file, "%u, %i, %u\n", f_target, rssi_max, high_count); if (i < 0) { MSG("ERROR: impossible to write to log file %s\n", log_file_name); return EXIT_FAILURE; } /* reset MCU and take back control of radio */ lgw_reg_w(LGW_MCU_RST_1, 1); lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL,1); /* iterate loop */ f_target += f_step; } fclose(log_file); lgw_soft_reset(); lgw_disconnect(); printf("Exiting band survey program\n"); return EXIT_SUCCESS; }
int main(int argc, char **argv) { int i; int xi = 0; /* application option */ int test_number = 1; int cycle_number = 0; int repeats_per_cycle = 1000; bool error = false; /* in/out variables */ int32_t test_value; int32_t read_value; int32_t rb1, rb2, rb3; /* interstitial readbacks, to flush buffers if needed */ /* data buffer */ int32_t test_addr; uint8_t test_buff[BUFF_SIZE]; uint8_t read_buff[BUFF_SIZE]; /* parse command line options */ while ((i = getopt (argc, argv, "ht:")) != -1) { switch (i) { case 'h': usage(); return EXIT_FAILURE; break; case 't': i = sscanf(optarg, "%i", &xi); if ((i != 1) || (xi < 1) || (xi > 4)) { MSG("ERROR: invalid test number\n"); return EXIT_FAILURE; } else { test_number = xi; } break; default: MSG("ERROR: argument parsing use -h option for help\n"); usage(); return EXIT_FAILURE; } } MSG("INFO: Starting LoRa concentrator SPI stress-test number %i\n", test_number); /* 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); /* start SPI link */ i = lgw_connect(); if (i != LGW_REG_SUCCESS) { MSG("ERROR: lgw_connect() did not return SUCCESS"); return EXIT_FAILURE; } if (test_number == 1) { /* single 8b register R/W stress test */ while ((quit_sig != 1) && (exit_sig != 1)) { printf("Cycle %i > ", cycle_number); for (i=0; i<repeats_per_cycle; ++i) { test_value = (rand() % 256); lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value); lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); if (read_value != test_value) { error = true; break; } } if (error) { printf("error during the %ith iteration: write 0x%02X, read 0x%02X\n", i+1, test_value, read_value); printf("Repeat read of target register:"); for (i=0; i<READS_WHEN_ERROR; ++i) { lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); printf(" 0x%02X", read_value); } printf("\n"); return EXIT_FAILURE; } else { printf("did %i R/W on an 8 bits reg with no error\n", repeats_per_cycle); ++cycle_number; } } } else if (test_number == 2) { /* single 8b register R/W with interstitial VERSION check stress test */ while ((quit_sig != 1) && (exit_sig != 1)) { printf("Cycle %i > ", cycle_number); for (i=0; i<repeats_per_cycle; ++i) { test_value = (rand() % 256); lgw_reg_r(LGW_VERSION, &rb1); lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value); lgw_reg_r(LGW_VERSION, &rb2); lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); lgw_reg_r(LGW_VERSION, &rb3); if ((rb1 != VERS) || (rb2 != VERS) || (rb3 != VERS) || (read_value != test_value)) { error = true; break; } } if (error) { printf("error during the %ith iteration: write %02X, read %02X, version (%i, %i, %i)\n", i+1, test_value, read_value, rb1, rb2, rb3); printf("Repeat read of target register:"); for (i=0; i<READS_WHEN_ERROR; ++i) { lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); printf(" 0x%02X", read_value); } printf("\n"); return EXIT_FAILURE; } else { printf("did %i R/W on an 8 bits reg with no error\n", repeats_per_cycle); ++cycle_number; } } } else if (test_number == 3) { /* 32b register R/W stress test */ while ((quit_sig != 1) && (exit_sig != 1)) { printf("Cycle %i > ", cycle_number); for (i=0; i<repeats_per_cycle; ++i) { test_value = (rand() & 0x0000FFFF); test_value += (int32_t)(rand() & 0x0000FFFF) << 16; lgw_reg_w(LGW_FSK_REF_PATTERN_LSB, test_value); lgw_reg_r(LGW_FSK_REF_PATTERN_LSB, &read_value); if (read_value != test_value) { error = true; break; } } if (error) { printf("error during the %ith iteration: write 0x%08X, read 0x%08X\n", i+1, test_value, read_value); printf("Repeat read of target register:"); for (i=0; i<READS_WHEN_ERROR; ++i) { lgw_reg_r(LGW_FSK_REF_PATTERN_LSB, &read_value); printf(" 0x%08X", read_value); } printf("\n"); return EXIT_FAILURE; } else { printf("did %i R/W on a 32 bits reg with no error\n", repeats_per_cycle); ++cycle_number; } } } else if (test_number == 4) { /* databuffer R/W stress test */ while ((quit_sig != 1) && (exit_sig != 1)) { for (i=0; i<BUFF_SIZE; ++i) { test_buff[i] = rand() & 0xFF; } printf("Cycle %i > ", cycle_number); test_addr = rand() & 0xFFFF; lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* write at random offset in memory */ lgw_reg_wb(LGW_RX_DATA_BUF_DATA, test_buff, BUFF_SIZE); lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* go back to start of segment */ lgw_reg_rb(LGW_RX_DATA_BUF_DATA, read_buff, BUFF_SIZE); for (i=0; ((i<BUFF_SIZE) && (test_buff[i] == read_buff[i])); ++i); if (i != BUFF_SIZE) { printf("error during the buffer comparison\n"); printf("Written values:\n"); for (i=0; i<BUFF_SIZE; ++i) { printf(" %02X ", test_buff[i]); if (i%16 == 15) printf("\n"); } printf("\n"); printf("Read values:\n"); for (i=0; i<BUFF_SIZE; ++i) { printf(" %02X ", read_buff[i]); if (i%16 == 15) printf("\n"); } printf("\n"); lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* go back to start of segment */ lgw_reg_rb(LGW_RX_DATA_BUF_DATA, read_buff, BUFF_SIZE); printf("Re-read values:\n"); for (i=0; i<BUFF_SIZE; ++i) { printf(" %02X ", read_buff[i]); if (i%16 == 15) printf("\n"); } printf("\n"); return EXIT_FAILURE; } else { printf("did a %i-byte R/W on a data buffer with no error\n", BUFF_SIZE); ++cycle_number; } } } else { MSG("ERROR: invalid test number"); usage(); } /* close SPI link */ i = lgw_disconnect(); if (i != LGW_REG_SUCCESS) { MSG("ERROR: lgw_disconnect() did not return SUCCESS"); return EXIT_FAILURE; } MSG("INFO: Exiting LoRa concentrator SPI stress-test program\n"); return EXIT_SUCCESS; }
int main(int argc, char **argv) { int i; int xi = 0; /* in/out variables */ double f1 = 0.0; uint32_t f_init = 0; /* in Hz */ uint32_t f_start = 0; /* in Hz */ uint16_t loop_cnt = 0; int8_t rssi_target_dBm = -80; uint16_t scan_time_us = 128; uint32_t timestamp; uint8_t rssi_value; int8_t rssi_offset = DEFAULT_SX127X_RSSI_OFFSET; int32_t val, val2; int channel; uint32_t freq_offset; /* parse command line options */ while ((i = getopt (argc, argv, "h:f:s:r:o:")) != -1) { switch (i) { case 'h': usage(); return EXIT_FAILURE; break; case 'f': i = sscanf(optarg, "%lf", &f1); if ((i != 1) || (f1 < 30.0) || (f1 > 3000.0)) { MSG("ERROR: Invalid LBT start frequency\n"); usage(); return EXIT_FAILURE; } else { f_start = (uint32_t)((f1*1e6) + 0.5);/* .5 Hz offset to get rounding instead of truncating */ } break; case 's': i = sscanf(optarg, "%i", &xi); if ((i != 1) || ((xi != 128) && (xi != 5000))) { MSG("ERROR: scan_time_us must be 128 or 5000 \n"); usage(); return EXIT_FAILURE; } else { scan_time_us = xi; } break; case 'r': i = sscanf(optarg, "%i", &xi); if ((i != 1) || ((xi < -128) && (xi > 0))) { MSG("ERROR: rssi_target must be b/w -128 & 0 \n"); usage(); return EXIT_FAILURE; } else { rssi_target_dBm = xi; } break; case 'o': /* -o <int> SX127x RSSI offset [-128..127] */ i = sscanf(optarg, "%i", &xi); if((i != 1) || (xi < -128) || (xi > 127)) { MSG("ERROR: rssi_offset must be b/w -128 & 127\n"); usage(); return EXIT_FAILURE; } else { rssi_offset = (int8_t)xi; } break; default: MSG("ERROR: argument parsing use -h option for help\n"); usage(); return EXIT_FAILURE; } } MSG("INFO: Starting LoRa Gateway v1.5 LBT test\n"); /* 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); /* Connect to concentrator */ i = lgw_connect(false, LGW_DEFAULT_NOTCH_FREQ); if (i != LGW_REG_SUCCESS) { MSG("ERROR: lgw_connect() did not return SUCCESS\n"); return EXIT_FAILURE; } /* Check if FPGA supports LBT */ lgw_fpga_reg_r(LGW_FPGA_FEATURE, &val); if (TAKE_N_BITS_FROM((uint8_t)val, 2, 1) != true) { MSG("ERROR: LBT is not supported (0x%x)\n", (uint8_t)val); return EXIT_FAILURE; } /* Get FPGA lowest frequency for LBT channels */ lgw_fpga_reg_r(LGW_FPGA_LBT_INITIAL_FREQ, &val); switch (val) { case 0: f_init = 915000000; break; case 1: f_init = 863000000; break; default: MSG("ERROR: LBT start frequency %d is not supported\n", val); return EXIT_FAILURE; } /* Initialize 1st LBT channel freq if not given by user */ if (f_start == 0) { f_start = f_init; } else if (f_start < f_init) { MSG("ERROR: LBT start frequency %u is not supported (f_init=%u)\n", f_start, f_init); return EXIT_FAILURE; } MSG("FREQ: %u\n", f_start); /* Configure SX127x and read few RSSI points */ lgw_setup_sx127x(f_init, MOD_FSK, LGW_SX127X_RXBW_100K_HZ, rssi_offset); /* 200KHz LBT channels */ for (i = 0; i < 100; i++) { lgw_sx127x_reg_r(0x11, &rssi_value); /* 0x11: RegRssiValue */ MSG("SX127x RSSI:%i dBm\n", -(rssi_value/2)); wait_ms(10); } /* Configure LBT */ val = -2*(rssi_target_dBm); lgw_fpga_reg_w(LGW_FPGA_RSSI_TARGET, val); for (i = 0; i < LBT_CHANNEL_FREQ_NB; i++) { freq_offset = (f_start - f_init)/100E3 + i*2; /* 200KHz between each channel */ lgw_fpga_reg_w(LGW_FPGA_LBT_CH0_FREQ_OFFSET+i, (int32_t)freq_offset); if (scan_time_us == 5000) { /* configured to 128 by default */ lgw_fpga_reg_w(LGW_FPGA_LBT_SCAN_TIME_CH0+i, 1); } } lgw_fpga_reg_r(LGW_FPGA_RSSI_TARGET, &val); MSG("RSSI_TARGET = %d\n", val); if (val != (-2*rssi_target_dBm)) { MSG("ERROR: failed to read back RSSI target register value\n"); return EXIT_FAILURE; } for (i = 0; i < LBT_CHANNEL_FREQ_NB; i++) { lgw_fpga_reg_r(LGW_FPGA_LBT_CH0_FREQ_OFFSET+i, &val); lgw_fpga_reg_r(LGW_FPGA_LBT_SCAN_TIME_CH0+i, &val2); MSG("CH_%i: freq=%u (offset=%i), scan_time=%u (%i)\n", i, (uint32_t)((val*100E3)+f_init), val, (val2==1)?5000:128, val2); } lgw_fpga_reg_r(LGW_FPGA_VERSION, &val); MSG("FPGA VERSION = %d\n", val); /* Enable LBT FSM */ lgw_fpga_reg_w(LGW_FPGA_CTRL_FEATURE_START, 1); /* Start test */ while ((quit_sig != 1) && (exit_sig != 1)) { MSG("~~~~\n"); for (channel = 0; channel < LBT_CHANNEL_FREQ_NB; channel++) { /* Select LBT channel */ lgw_fpga_reg_w(LGW_FPGA_LBT_TIMESTAMP_SELECT_CH, channel); /* Get last instant when the selected channel was free */ lgw_fpga_reg_r(LGW_FPGA_LBT_TIMESTAMP_CH, &val); timestamp = (uint32_t)(val & 0x0000FFFF) * 256; /* 16bits (1LSB = 256µs) */ MSG(" TIMESTAMP_CH%u = %u\n", channel, timestamp); } loop_cnt += 1; wait_ms(400); } /* close SPI link */ i = lgw_disconnect(); if (i != LGW_REG_SUCCESS) { MSG("ERROR: lgw_disconnect() did not return SUCCESS\n"); return EXIT_FAILURE; } MSG("INFO: Exiting LoRa Gateway v1.5 LBT test successfully\n"); return EXIT_SUCCESS; }