* Initial release for SX1302 CoreCell Reference Design.
This commit is contained in:
Michael Coracin 2019-07-12 15:40:13 +02:00
commit 4c61c5d48e
79 changed files with 30157 additions and 0 deletions

View file

@ -0,0 +1,698 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2019 Semtech
Description:
Minimum test program for HAL calibration
License: Revised BSD License, see LICENSE.TXT file include in the project
*/
/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */
/* fix an issue between POSIX and C99 */
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <signal.h> /* sigaction */
#include <getopt.h> /* getopt_long */
#include <sys/time.h>
#include "loragw_hal.h"
#include "loragw_reg.h"
#include "loragw_sx1302.h"
#include "loragw_sx125x.h"
#include "loragw_aux.h"
#include "loragw_cal.h"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
#define RAND_RANGE(min, max) (rand() % (max + 1 - min) + min)
#define DEBUG_MSG(str) fprintf(stderr, str)
#define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
/* -------------------------------------------------------------------------- */
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
#define LINUXDEV_PATH_DEFAULT "/dev/spidev0.0"
#define DEFAULT_CLK_SRC 0
#define DEFAULT_FREQ_HZ 868500000U
#define DEFAULT_DAC_GAIN 3
#define DEFAULT_MIX_GAIN 15
#define CAL_TX_TONE_FREQ_HZ 250000
#define CAL_DEC_GAIN 8
#define CAL_SIG_ANA_DURATION 0 /* correlation duration: 0:1, 1:2, 2:4, 3:8 ms) */
#define TEST_FREQ_SCAN 0
#define TEST_OFFSET_IQ 1
#define TEST_AMP_PHI 2
/* -------------------------------------------------------------------------- */
/* --- PRIVATE TYPES -------------------------------------------------------- */
struct cal_tx_log {
int32_t mean;
int32_t i_offset;
int32_t q_offset;
};
/* -------------------------------------------------------------------------- */
/* --- PRIVATE VARIABLES ---------------------------------------------------- */
FILE * fp;
static uint32_t rf_rx_freq[LGW_RF_CHAIN_NB] = {865500000, 865500000};
static lgw_radio_type_t rf_radio_type[LGW_RF_CHAIN_NB] = {LGW_RADIO_TYPE_SX1257, LGW_RADIO_TYPE_SX1257};
static struct lgw_tx_gain_lut_s txlut; /* TX gain table */
/* Signal handling variables */
static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
#include "../src/cal_fw.var" /* text_cal_sx1257_16_Nov_1 */
/* -------------------------------------------------------------------------- */
/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
/* describe command line options */
void usage(void) {
//printf("Library version information: %s\n", lgw_version_info());
printf("Available options:\n");
printf(" -h print this help\n");
printf(" -d <path> use Linux SPI device driver\n");
printf(" => default path: " LINUXDEV_PATH_DEFAULT "\n");
printf(" -k <uint> Concentrator clock source (Radio A or Radio B) [0..1]\n");
printf(" -c <uint> RF chain to be used for TX (Radio A or Radio B) [0..1]\n");
printf(" -r <uint> Radio type (1255, 1257, 1250)\n");
printf(" -f <float> Radio TX frequency in MHz\n");
printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
printf(" --pa <uint> PA gain [0..3]\n");
printf(" --dig <uint> sx1302 digital gain [0..3]\n");
printf(" --dac <uint> sx1257 DAC gain [0..3]\n");
printf(" --mix <uint> sx1257 MIX gain [0..15]\n");
}
/* handle signals */
static void sig_handler(int sigio)
{
if (sigio == SIGQUIT) {
quit_sig = 1;
}
else if((sigio == SIGINT) || (sigio == SIGTERM)) {
exit_sig = 1;
}
}
int setup_tx_dc_offset(uint8_t rf_chain, uint32_t freq_hz, uint8_t dac_gain, uint8_t mix_gain, uint8_t radio_type) {
uint32_t rx_freq_hz, tx_freq_hz;
uint32_t rx_freq_int, rx_freq_frac;
uint32_t tx_freq_int, tx_freq_frac;
uint8_t rx_pll_locked, tx_pll_locked;
/* Set PLL frequencies */
rx_freq_hz = freq_hz - CAL_TX_TONE_FREQ_HZ;
tx_freq_hz = freq_hz;
switch (radio_type) {
case LGW_RADIO_TYPE_SX1255:
rx_freq_int = rx_freq_hz / (SX125x_32MHz_FRAC << 7); /* integer part, gives the MSB */
rx_freq_frac = ((rx_freq_hz % (SX125x_32MHz_FRAC << 7)) << 9) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */
tx_freq_int = tx_freq_hz / (SX125x_32MHz_FRAC << 7); /* integer part, gives the MSB */
tx_freq_frac = ((tx_freq_hz % (SX125x_32MHz_FRAC << 7)) << 9) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */
break;
case LGW_RADIO_TYPE_SX1257:
rx_freq_int = rx_freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */
rx_freq_frac = ((rx_freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */
tx_freq_int = tx_freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */
tx_freq_frac = ((tx_freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */
break;
default:
DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d FOR RADIO TYPE\n", radio_type);
return LGW_HAL_ERROR;
}
lgw_sx125x_reg_w(SX125x_REG_FRF_RX_MSB, 0xFF & rx_freq_int, rf_chain);
lgw_sx125x_reg_w(SX125x_REG_FRF_RX_MID, 0xFF & (rx_freq_frac >> 8), rf_chain);
lgw_sx125x_reg_w(SX125x_REG_FRF_RX_LSB, 0xFF & rx_freq_frac, rf_chain);
lgw_sx125x_reg_w(SX125x_REG_FRF_TX_MSB, 0xFF & tx_freq_int, rf_chain);
lgw_sx125x_reg_w(SX125x_REG_FRF_TX_MID, 0xFF & (tx_freq_frac >> 8), rf_chain);
lgw_sx125x_reg_w(SX125x_REG_FRF_TX_LSB, 0xFF & tx_freq_frac, rf_chain);
/* Radio settings for calibration */
//lgw_sx125x_reg_w(SX125x_RX_ANA_GAIN__LNA_ZIN, 1, rf_chain); /* Default: 1 */
//lgw_sx125x_reg_w(SX125x_RX_ANA_GAIN__BB_GAIN, 15, rf_chain); /* Default: 15 */
//lgw_sx125x_reg_w(SX125x_RX_ANA_GAIN__LNA_GAIN, 1, rf_chain); /* Default: 1 */
lgw_sx125x_reg_w(SX125x_REG_RX_BW__BB_BW, 0, rf_chain);
lgw_sx125x_reg_w(SX125x_REG_RX_BW__ADC_TRIM, 6, rf_chain);
//lgw_sx125x_reg_w(SX125x_RX_BW__ADC_BW, 7, rf_chain); /* Default: 7 */
lgw_sx125x_reg_w(SX125x_REG_RX_PLL_BW__PLL_BW, 0, rf_chain);
lgw_sx125x_reg_w(SX125x_REG_TX_BW__PLL_BW, 0, rf_chain);
//lgw_sx125x_reg_w(SX125x_TX_BW__ANA_BW, 0, rf_chain); /* Default: 0 */
lgw_sx125x_reg_w(SX125x_REG_TX_DAC_BW, 5, rf_chain);
lgw_sx125x_reg_w(SX125x_REG_CLK_SELECT__DAC_CLK_SELECT, 1, rf_chain); /* Use external clock from SX1302 */
lgw_sx125x_reg_w(SX125x_REG_TX_GAIN__DAC_GAIN, dac_gain, rf_chain);
lgw_sx125x_reg_w(SX125x_REG_TX_GAIN__MIX_GAIN, mix_gain, rf_chain);
lgw_sx125x_reg_w(SX125x_REG_CLK_SELECT__RF_LOOPBACK_EN, 1, rf_chain);
lgw_sx125x_reg_w(SX125x_REG_MODE, 15, rf_chain);
wait_ms(1);
lgw_sx125x_reg_r(SX125x_REG_MODE_STATUS__RX_PLL_LOCKED, &rx_pll_locked, rf_chain);
lgw_sx125x_reg_r(SX125x_REG_MODE_STATUS__TX_PLL_LOCKED, &tx_pll_locked, rf_chain);
if ((rx_pll_locked == 0) || (tx_pll_locked == 0)) {
DEBUG_MSG("ERROR: PLL failed to lock\n");
return LGW_HAL_ERROR;
}
return 0;
}
int cal_tx_dc_offset(uint8_t test_id, uint8_t rf_chain, uint32_t freq_hz, uint8_t dac_gain, uint8_t mix_gain, uint8_t radio_type, int32_t f_offset, int32_t i_offset, int32_t q_offset, bool full_log, bool use_agc, uint8_t amp, uint8_t phi) {
int i;
uint16_t reg;
int32_t val_min, val_max;
int32_t acc;
int32_t val_mean;
float val_std;
float acc2 = 0 ;
int loop_len = 3;
float res_sig[loop_len];
struct timeval start, stop;
//DEBUG_MSG("\n");
//DEBUG_PRINTF("rf_chain:%u, freq_hz:%u, dac_gain:%u, mix_gain:%u, radio_type:%d\n", rf_chain, freq_hz, dac_gain, mix_gain, radio_type);
if (setup_tx_dc_offset(rf_chain, freq_hz, dac_gain, mix_gain, radio_type) != LGW_HAL_SUCCESS) {
return LGW_HAL_ERROR;
}
/* Trig calibration */
/* Select radio to be connected to the Signal Analyzer (warning: RadioA:1, RadioB:0) */
lgw_reg_w(SX1302_REG_RADIO_FE_SIG_ANA_CFG_RADIO_SEL, (rf_chain == 0) ? 1 : 0);
reg = REG_SELECT(rf_chain, SX1302_REG_TX_TOP_A_TX_RFFE_IF_CTRL_TX_MODE,
SX1302_REG_TX_TOP_B_TX_RFFE_IF_CTRL_TX_MODE);
lgw_reg_w(reg, 0);
reg = REG_SELECT(rf_chain, SX1302_REG_TX_TOP_A_TX_TRIG_TX_TRIG_IMMEDIATE,
SX1302_REG_TX_TOP_B_TX_TRIG_TX_TRIG_IMMEDIATE);
lgw_reg_w(reg, 1);
lgw_reg_w(reg, 0);
reg = REG_SELECT(rf_chain, SX1302_REG_RADIO_FE_CTRL0_RADIO_A_DC_NOTCH_EN,
SX1302_REG_RADIO_FE_CTRL0_RADIO_B_DC_NOTCH_EN);
lgw_reg_w(reg, 1);
/* Measuring */
if (use_agc == true) {
uint8_t val_sig, val_sig2;
/* Set calibration parameters */
sx1302_agc_mailbox_write(2, rf_chain + 4); /* Sig ana test radio A/B */
sx1302_agc_mailbox_write(1, f_offset/*(CAL_TX_TONE_FREQ_HZ + f_offset) * 64e-6*/); /* Set frequency */
sx1302_agc_mailbox_write(0, CAL_SIG_ANA_DURATION);
/* */
sx1302_agc_mailbox_write(3, 0x00);
sx1302_agc_mailbox_write(3, 0x01);
sx1302_agc_wait_status(0x01);
sx1302_agc_mailbox_write(2, amp); /* amp */
sx1302_agc_mailbox_write(1, phi); /* phi */
sx1302_agc_mailbox_write(3, 0x02);
sx1302_agc_wait_status(0x02);
sx1302_agc_mailbox_write(2, i_offset); /* i offset init */
sx1302_agc_mailbox_write(1, q_offset); /* q offset init */
sx1302_agc_mailbox_write(3, 0x03);
sx1302_agc_wait_status(0x03);
sx1302_agc_mailbox_write(2, CAL_DEC_GAIN); /* dec_gain */
sx1302_agc_mailbox_write(2, 0); /* threshold (not used) */
sx1302_agc_mailbox_write(3, 0x04);
reg = REG_SELECT(rf_chain, SX1302_REG_TX_TOP_A_TX_TRIG_TX_TRIG_IMMEDIATE,
SX1302_REG_TX_TOP_B_TX_TRIG_TX_TRIG_IMMEDIATE);
lgw_reg_w(reg, 0);
gettimeofday (&start, NULL);
for (i = 0; i < loop_len; i++) {
sx1302_agc_wait_status(0x06);
sx1302_agc_mailbox_write(3, 0x06);
sx1302_agc_wait_status(0x07);
sx1302_agc_mailbox_read(0, &val_sig);
sx1302_agc_mailbox_read(1, &val_sig2);
res_sig[i] = val_sig2 * 256 + val_sig;
if (i == (loop_len - 1)) {
sx1302_agc_mailbox_write(3, 0x07); /* unlock */
} else {
sx1302_agc_mailbox_write(3, 0x00); /* unlock */
}
}
gettimeofday (&stop, NULL);
//printf("processing time: %ld us\n", ((stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec) - start.tv_usec);
} else {
int32_t val;
int32_t abs_lsb, abs_msb;
float abs_iq;
reg = REG_SELECT(rf_chain, SX1302_REG_TX_TOP_A_TX_RFFE_IF_Q_OFFSET_Q_OFFSET,
SX1302_REG_TX_TOP_B_TX_RFFE_IF_Q_OFFSET_Q_OFFSET);
lgw_reg_w(reg, (int8_t)q_offset);
reg = REG_SELECT(rf_chain, SX1302_REG_TX_TOP_A_TX_RFFE_IF_I_OFFSET_I_OFFSET,
SX1302_REG_TX_TOP_B_TX_RFFE_IF_I_OFFSET_I_OFFSET);
lgw_reg_w(reg, (int8_t)i_offset);
reg = REG_SELECT(rf_chain, SX1302_REG_RADIO_FE_CTRL0_RADIO_A_DC_NOTCH_EN,
SX1302_REG_RADIO_FE_CTRL0_RADIO_B_DC_NOTCH_EN);
lgw_reg_w(reg, 1);
reg = REG_SELECT(rf_chain, SX1302_REG_RADIO_FE_CTRL0_RADIO_A_FORCE_HOST_FILTER_GAIN,
SX1302_REG_RADIO_FE_CTRL0_RADIO_B_FORCE_HOST_FILTER_GAIN);
lgw_reg_w(reg, 0x01);
reg = REG_SELECT(rf_chain, SX1302_REG_RADIO_FE_CTRL0_RADIO_A_HOST_FILTER_GAIN,
SX1302_REG_RADIO_FE_CTRL0_RADIO_B_HOST_FILTER_GAIN);
lgw_reg_w(reg, CAL_DEC_GAIN);
lgw_reg_w(SX1302_REG_RADIO_FE_SIG_ANA_CFG_FORCE_HAL_CTRL, 1);
lgw_reg_w(SX1302_REG_RADIO_FE_SIG_ANA_FREQ_FREQ, f_offset);
lgw_reg_w(SX1302_REG_RADIO_FE_SIG_ANA_CFG_DURATION, CAL_SIG_ANA_DURATION);
lgw_reg_w(SX1302_REG_RADIO_FE_SIG_ANA_CFG_EN, 1);
gettimeofday (&start, NULL);
for (i = 0; i < loop_len; i++) {
lgw_reg_w(SX1302_REG_RADIO_FE_SIG_ANA_CFG_START, 0);
lgw_reg_w(SX1302_REG_RADIO_FE_SIG_ANA_CFG_START, 1);
do {
lgw_reg_r(SX1302_REG_RADIO_FE_SIG_ANA_CFG_VALID, &val);
wait_ms(1);
} while (val == 0);
lgw_reg_r(SX1302_REG_RADIO_FE_SIG_ANA_ABS_LSB_CORR_ABS_OUT, &abs_lsb);
lgw_reg_r(SX1302_REG_RADIO_FE_SIG_ANA_ABS_MSB_CORR_ABS_OUT, &abs_msb);
abs_iq = (abs_msb << 8) | abs_lsb;
res_sig[i] = abs_iq;
}
gettimeofday (&stop, NULL);
//printf("processing time: %ld us\n", ((stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec) - start.tv_usec);
lgw_reg_w(SX1302_REG_RADIO_FE_SIG_ANA_CFG_FORCE_HAL_CTRL, 0);
}
if (full_log == true) {
printf("i_offset:%d q_offset:%d f_offset:%d dac_gain:%d mix_gain:%d dec_gain:%d amp:%u phi:%u => ", i_offset, q_offset, f_offset, dac_gain, mix_gain, CAL_DEC_GAIN, amp, phi);
} else {
switch (test_id) {
case TEST_FREQ_SCAN:
fprintf(fp, "%u ", f_offset);
break;
case TEST_OFFSET_IQ:
fprintf(fp, "%d %d ", i_offset, q_offset);
break;
case TEST_AMP_PHI:
fprintf(fp, "%d %d ", amp, phi);
break;
default:
printf("ERROR: wrong test ID (%u)\n", test_id);
break;
}
}
/* Analyze result */
val_min = res_sig[0];
val_max = res_sig[0];
acc = 0;
for (i = 0; i < loop_len; i++) {
if (res_sig[i] > val_max) {
val_max = res_sig[i];
}
if (res_sig[i] < val_min) {
val_min = res_sig[i];
}
acc += res_sig[i];
}
val_mean = acc / loop_len;
for (i = 0; i < loop_len; i++) {
acc2 += pow((res_sig[i]-val_mean),2);
}
val_std = sqrt(acc2/loop_len);
if (full_log == true) {
printf(" min:%u max:%u mean:%u std:%f\n", val_min, val_max, val_mean, val_std);
} else {
switch (test_id) {
case TEST_OFFSET_IQ:
case TEST_AMP_PHI:
fprintf(fp, "%u %u %u %f\n", val_min, val_max, val_mean, val_std);
break;
case TEST_FREQ_SCAN:
fprintf(fp, "%u\n", val_mean);
break;
default:
break;
}
}
return LGW_HAL_SUCCESS;
}
/* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */
int test_freq_scan(uint8_t rf_chain, bool full_log, bool use_agc) {
int f;
printf("-------------------------------------\n");
for (f = 0; f < 256; f++)
{
cal_tx_dc_offset(TEST_FREQ_SCAN, rf_chain, rf_rx_freq[rf_chain], txlut.lut[0].dac_gain, txlut.lut[0].mix_gain, rf_radio_type[rf_chain], f, 0, 0, full_log, use_agc, 0, 0);
if ((quit_sig == 1) || (exit_sig == 1)) {
break;
}
}
return 0;
}
int test_iq_offset(uint8_t rf_chain, uint8_t f_offset, bool full_log, bool use_agc) {
int i, q;
printf("-------------------------------------\n");
for (i = -128; i < 127; i+=8)
{
for (q = -128; q < 127; q+=8)
{
cal_tx_dc_offset(TEST_OFFSET_IQ, rf_chain, rf_rx_freq[rf_chain], txlut.lut[0].dac_gain, txlut.lut[0].mix_gain, rf_radio_type[rf_chain], f_offset, i, q, full_log, use_agc, 0, 0);
if ((quit_sig == 1) || (exit_sig == 1)) {
return 0;
}
}
}
return 0;
}
int test_amp_phi(uint8_t rf_chain, uint8_t f_offset, bool full_log, bool use_agc) {
int amp, phi;
printf("-------------------------------------\n");
for (amp = 0; amp < 64; amp++)
{
for (phi = 0; phi < 64; phi++)
{
cal_tx_dc_offset(TEST_AMP_PHI, rf_chain, rf_rx_freq[rf_chain], txlut.lut[0].dac_gain, txlut.lut[0].mix_gain, rf_radio_type[rf_chain], f_offset, 0, 0, full_log, use_agc, amp, phi);
if ((quit_sig == 1) || (exit_sig == 1)) {
return 0;
}
}
}
return 0;
}
int test_capture_ram(uint8_t rf_chain) {
uint16_t reg;
setup_tx_dc_offset(rf_chain, rf_rx_freq[rf_chain], txlut.lut[0].dac_gain, txlut.lut[0].mix_gain, rf_radio_type[rf_chain]);
reg = REG_SELECT(rf_chain, SX1302_REG_RADIO_FE_CTRL0_RADIO_A_DC_NOTCH_EN,
SX1302_REG_RADIO_FE_CTRL0_RADIO_B_DC_NOTCH_EN);
lgw_reg_w(reg, 1);
printf("Waiting...\n");
while ((quit_sig != 1) && (exit_sig != 1)) {
wait_ms(1000);
}
return 0;
}
int main(int argc, char **argv)
{
int i, x;
uint32_t ft = DEFAULT_FREQ_HZ;
double arg_d = 0.0;
unsigned int arg_u;
uint8_t clocksource = 0;
uint8_t rf_chain = 0;
lgw_radio_type_t radio_type = LGW_RADIO_TYPE_NONE;
struct lgw_conf_board_s boardconf;
struct lgw_conf_rxrf_s rfconf;
static struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
/* SPI interfaces */
const char spidev_path_default[] = LINUXDEV_PATH_DEFAULT;
const char * spidev_path = spidev_path_default;
/* Initialize TX gain LUT */
txlut.size = 1;
memset(txlut.lut, 0, sizeof txlut.lut);
txlut.lut[0].dac_gain = DEFAULT_DAC_GAIN;
txlut.lut[0].mix_gain = DEFAULT_MIX_GAIN;
/* Parameter parsing */
int option_index = 0;
static struct option long_options[] = {
{"dac", 1, 0, 0},
{"mix", 1, 0, 0},
{0, 0, 0, 0}
};
/* parse command line options */
while ((i = getopt_long (argc, argv, "hf:k:r:c:d:", long_options, &option_index)) != -1) {
switch (i) {
case 'h':
usage();
return -1;
break;
case 'd':
if (optarg != NULL) {
spidev_path = optarg;
}
break;
case 'r': /* <uint> Radio type */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || ((arg_u != 1255) && (arg_u != 1257) && (arg_u != 1250))) {
printf("ERROR: argument parsing of -r argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
switch (arg_u) {
case 1255:
radio_type = LGW_RADIO_TYPE_SX1255;
break;
case 1257:
radio_type = LGW_RADIO_TYPE_SX1257;
break;
default: /* 1250 */
radio_type = LGW_RADIO_TYPE_SX1250;
break;
}
}
break;
case 'k': /* <uint> Clock Source */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 1)) {
printf("ERROR: argument parsing of -k argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
clocksource = (uint8_t)arg_u;
}
break;
case 'c': /* <uint> RF chain */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 1)) {
printf("ERROR: argument parsing of -c argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
rf_chain = (uint8_t)arg_u;
}
break;
case 'f': /* <float> Radio TX frequency in MHz */
i = sscanf(optarg, "%lf", &arg_d);
if (i != 1) {
printf("ERROR: argument parsing of -f argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
ft = (uint32_t)((arg_d*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
}
break;
case 0:
if (strcmp(long_options[option_index].name, "dac") == 0) {
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 3)) {
printf("ERROR: argument parsing of --dac argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
txlut.size = 1;
txlut.lut[0].dac_gain = (uint8_t)arg_u;
}
} else if (strcmp(long_options[option_index].name, "mix") == 0) {
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 15)) {
printf("ERROR: argument parsing of --mix argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
txlut.size = 1;
txlut.lut[0].mix_gain = (uint8_t)arg_u;
}
} else {
printf("ERROR: argument parsing options. Use -h to print help\n");
return EXIT_FAILURE;
}
break;
default:
printf("ERROR: argument parsing\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 );
/* Board reset */
if (system("./reset_lgw.sh start") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
/* Configure the gateway */
memset(&boardconf, 0, sizeof boardconf);
boardconf.lorawan_public = true;
boardconf.clksrc = clocksource;
boardconf.full_duplex = false;
strncpy(boardconf.spidev_path, spidev_path, sizeof boardconf.spidev_path);
if (lgw_board_setconf(&boardconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure board\n");
return EXIT_FAILURE;
}
memset(&rfconf, 0, sizeof rfconf);
rfconf.enable = ((rf_chain == 0) ? true : false);
rfconf.freq_hz = ft;
rfconf.type = radio_type;
rfconf.tx_enable = true;
if (lgw_rxrf_setconf(0, &rfconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxrf 0\n");
return EXIT_FAILURE;
}
memset(&rfconf, 0, sizeof rfconf);
rfconf.enable = ((rf_chain == 1) ? true : false);
rfconf.freq_hz = ft;
rfconf.type = radio_type;
rfconf.tx_enable = true;
if (lgw_rxrf_setconf(1, &rfconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxrf 1\n");
return EXIT_FAILURE;
}
if (txlut.size > 0) {
if (lgw_txgain_setconf(rf_chain, &txlut) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure txgain lut\n");
return EXIT_FAILURE;
}
}
/* open log file for writing */
fp = fopen("log.txt", "w+");
/* connect the gateway */
x = lgw_connect(spidev_path);
if (x != 0) {
printf("ERROR: failed to connect the gateway\n");
return EXIT_FAILURE;
}
sx1302_radio_reset(rf_chain, LGW_RADIO_TYPE_SX1257);
sx1302_radio_clock_select(clocksource);
sx1302_radio_set_mode(rf_chain, LGW_RADIO_TYPE_SX1257);
printf("Loading CAL fw for sx125x\n");
if (sx1302_agc_load_firmware(cal_firmware_sx125x) != LGW_HAL_SUCCESS) {
return LGW_HAL_ERROR;
}
printf("waiting for capture ram\n");
wait_ms(1000);
/* testing */
printf("testing: rf_chain:%u, dac_gain: %u, mix_gain:%u, dec_gain:%u, sig_ana_duration:%u\n", rf_chain, txlut.lut[0].dac_gain, txlut.lut[0].mix_gain, CAL_DEC_GAIN, CAL_SIG_ANA_DURATION);
test_freq_scan(rf_chain, false, false); /* rf_chain, full_log, use_agc */
/* gnuplot> plot 'log.txt' with lines */
//test_iq_offset(rf_chain, 16, false, false); /* rf_chain, f_offset, full_log, use_agc */
//test_amp_phi(rf_chain, 240, true, true); /* rf_chain, f_offset, full_log, use_agc */
//test_capture_ram(rf_chain);
sx1302_radio_reset(0, LGW_RADIO_TYPE_SX1257);
sx1302_radio_reset(1, LGW_RADIO_TYPE_SX1257);
/* disconnect the gateway */
x = lgw_disconnect();
if (x != 0) {
printf("ERROR: failed to disconnect the gateway\n");
return EXIT_FAILURE;
}
/* Close log file */
fclose(fp);
/* Board reset */
if (system("./reset_lgw.sh stop") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
printf("=========== Test End ===========\n");
return 0;
}
/* --- EOF ------------------------------------------------------------------ */

View file

@ -0,0 +1,369 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2019 Semtech
Description:
Minimum test program to test the capture RAM block
License: Revised BSD License, see LICENSE.TXT file include in the project
*/
/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */
/* fix an issue between POSIX and C99 */
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif
// #include <stdint.h>
#include <stdio.h> /* printf */
#include <stdlib.h>
#include <signal.h> /* sigaction */
#include <getopt.h> /* getopt_long */
#include "loragw_hal.h"
#include "loragw_reg.h"
#include "loragw_aux.h"
#include "loragw_sx1250.h"
#include "loragw_sx125x.h"
#include "loragw_sx1302.h"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
#define DEBUG_MSG(str) fprintf(stderr, str)
#define LINUXDEV_PATH_DEFAULT "/dev/spidev0.0"
#define FULL_INIT 0
#define CAPTURE_RAM_SIZE 0x4000
/* -------------------------------------------------------------------------- */
/* --- PRIVATE VARIABLES ---------------------------------------------------- */
/* Signal handling variables */
static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
uint32_t sampling_frequency[] = {4e6, 4e6, 4e6, 4e6, 4e6, 4e6, 4e6, 0, 0, 1e6, 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 8e6, 125e3, 125e3, 125e3, 0, 32e6, 32e6, 0, 32e6, 32e6, 0, 32e6, 32e6, 32e6};
#if FULL_INIT
#include "src/text_agc_sx1250_27_Nov_1.var"
#include "src/text_agc_sx1257_19_Nov_1.var"
#include "src/text_arb_sx1302_13_Nov_3.var"
#define FW_VERSION_CAL 0 /* Expected version of calibration firmware */ /* TODO */
#define FW_VERSION_AGC 1 /* Expected version of AGC firmware */
#define FW_VERSION_ARB 1 /* Expected version of arbiter firmware */
static bool rf_enable[LGW_RF_CHAIN_NB];
static uint32_t rf_rx_freq[LGW_RF_CHAIN_NB]; /* absolute, in Hz */
static lgw_radio_type_t rf_radio_type[LGW_RF_CHAIN_NB];
static uint8_t rf_clkout = 0;
#endif
/* -------------------------------------------------------------------------- */
/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
/* describe command line options */
void usage(void)
{
printf("Available options:\n");
printf(" -h print this help\n");
printf(" -d <path> use Linux SPI device driver\n");
printf(" => default path: " LINUXDEV_PATH_DEFAULT "\n");
printf(" -s <uint> Capture source [0..31]\n");
}
/* handle signals */
static void sig_handler(int sigio)
{
if (sigio == SIGQUIT) {
quit_sig = 1;
}
else if((sigio == SIGINT) || (sigio == SIGTERM)) {
exit_sig = 1;
}
}
/* Main program */
int main(int argc, char **argv)
{
int i;
int32_t val = 0;
int reg_stat;
unsigned int arg_u;
uint8_t capture_source = 0;
uint16_t period_value = 0;
int16_t real = 0, imag = 0;
#if FULL_INIT
uint32_t val1, val2;
#endif
uint8_t capture_ram_buffer[CAPTURE_RAM_SIZE];
static struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
/* SPI interfaces */
const char spidev_path_default[] = LINUXDEV_PATH_DEFAULT;
const char * spidev_path = spidev_path_default;
/* Parameter parsing */
int option_index = 0;
static struct option long_options[] = {
{0, 0, 0, 0}
};
/* parse command line options */
while ((i = getopt_long (argc, argv, "h:s:d:", long_options, &option_index)) != -1) {
switch (i) {
case 'h':
usage();
return -1;
break;
case 'd':
if (optarg != NULL) {
spidev_path = optarg;
}
break;
case 's': /* <uint> Capture Source */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 31)) {
printf("ERROR: argument parsing of -s argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
capture_source = arg_u;
}
break;
default:
printf("ERROR: argument parsing\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 );
#if FULL_INIT
/* Board reset */
if (system("./reset_lgw.sh start") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
#endif
/* Initialize memory for capture */
for (i = 0; i < CAPTURE_RAM_SIZE; i++) {
capture_ram_buffer[i] = i%256;
}
reg_stat = lgw_connect(spidev_path);
if (reg_stat == LGW_REG_ERROR) {
DEBUG_MSG("ERROR: FAIL TO CONNECT BOARD\n");
return LGW_HAL_ERROR;
}
/* Manual init */
#if FULL_INIT
rf_radio_type[0] = LGW_RADIO_TYPE_SX1250;
rf_radio_type[1] = LGW_RADIO_TYPE_SX1257;
rf_enable[0] = false;
rf_enable[1] = true;
rf_clkout = 1;
rf_rx_freq[1] = 863700000;
/* setup radios */
for (i=0; i < 2; i++)
{
if (rf_enable[i] == true) {
sx1302_radio_reset(i, rf_radio_type[i]);
switch (radio_type) {
case LGW_RADIO_TYPE_SX1250:
sx1250_setup(i, rf_rx_freq[i]);
break;
case LGW_RADIO_TYPE_SX1255:
case LGW_RADIO_TYPE_SX1257:
sx125x_setup(i, rf_clkout, true, rf_radio_type[i], rf_rx_freq[i]);
break;
default:
DEBUG_MSG("ERROR: RADIO TYPE NOT SUPPORTED\n");
return LGW_HAL_ERROR;
}
sx1302_radio_set_mode(i, radio_type);
}
}
/* Select the radio which provides the clock to the sx1302 */
sx1302_radio_clock_select(rf_clkout);
/* Check that the SX1302 timestamp counter is running */
lgw_get_instcnt(&val1);
lgw_get_instcnt(&val2);
if (val1 == val2) {
printf("ERROR: SX1302 timestamp counter is not running (val:%u)\n", (uint32_t)val1);
return -1;
}
/* Configure Radio FE */
sx1302_radio_fe_configure();
/* give radio control to AGC MCU */
lgw_reg_w(SX1302_REG_COMMON_CTRL0_HOST_RADIO_CTRL, 0x00);
/* Load firmware */
switch (rf_radio_type[rf_clkout]) {
case LGW_RADIO_TYPE_SX1250:
printf("Loading AGC fw for sx1250\n");
if (sx1302_agc_load_firmware(agc_firmware_sx1250) != LGW_HAL_SUCCESS) {
return LGW_HAL_ERROR;
}
if (sx1302_agc_start(FW_VERSION_AGC, SX1302_RADIO_TYPE_SX1250, SX1302_AGC_RADIO_GAIN_AUTO, SX1302_AGC_RADIO_GAIN_AUTO, 0) != LGW_HAL_SUCCESS) {
return LGW_HAL_ERROR;
}
break;
case LGW_RADIO_TYPE_SX1257:
printf("Loading AGC fw for sx125x\n");
if (sx1302_agc_load_firmware(agc_firmware_sx125x) != LGW_HAL_SUCCESS) {
return LGW_HAL_ERROR;
}
if (sx1302_agc_start(FW_VERSION_AGC, SX1302_RADIO_TYPE_SX125X, SX1302_AGC_RADIO_GAIN_AUTO, SX1302_AGC_RADIO_GAIN_AUTO, 0) != LGW_HAL_SUCCESS) {
// if (sx1302_agc_start(FW_VERSION_AGC, SX1302_RADIO_TYPE_SX125X, 1, 7, 0) != LGW_HAL_SUCCESS) {
return LGW_HAL_ERROR;
}
break;
default:
break;
}
printf("Loading ARB fw\n");
if (sx1302_arb_load_firmware(arb_firmware) != LGW_HAL_SUCCESS) {
return LGW_HAL_ERROR;
}
if (sx1302_arb_start(FW_VERSION_ARB) != LGW_HAL_SUCCESS) {
return LGW_HAL_ERROR;
}
#endif
// lgw_reg_w(SX1302_REG_CAPTURE_RAM_CLOCK_GATE_OVERRIDE_CLK_OVERRIDE, 3);
/* Configure the Capture Ram block */
lgw_reg_w(SX1302_REG_CAPTURE_RAM_CAPTURE_CFG_ENABLE, 1); /* Enable Capture RAM */
lgw_reg_w(SX1302_REG_CAPTURE_RAM_CAPTURE_CFG_CAPTUREWRAP, 0); /* Capture once, and stop when memory is full */
lgw_reg_w(SX1302_REG_CAPTURE_RAM_CAPTURE_CFG_RAMCONFIG, 0); /* RAM configuration, 0: 4kx32, 1: 2kx64 */
fprintf(stdout, "Capture source: %d\n", capture_source);
lgw_reg_w(SX1302_REG_CAPTURE_RAM_CAPTURE_SOURCE_A_SOURCEMUX, capture_source);
printf("Sampling frequency: %d\n", sampling_frequency[capture_source]);
if (sampling_frequency[capture_source] != 0)
{
period_value = (32e6/sampling_frequency[capture_source]) - 1;
}
else
{
fprintf(stderr ,"ERROR: Sampling frequency is null\n");
return -1;
}
// fprintf(stdout, "period_value=%04X\n", period_value);
lgw_reg_w(SX1302_REG_CAPTURE_RAM_CAPTURE_PERIOD_0_CAPTUREPERIOD, period_value & 0xFF); // LSB
lgw_reg_w(SX1302_REG_CAPTURE_RAM_CAPTURE_PERIOD_1_CAPTUREPERIOD, (period_value>>8) & 0xFF); // MSB
/* Read back registers */
// lgw_reg_r(SX1302_REG_CAPTURE_RAM_CAPTURE_PERIOD_0_CAPTUREPERIOD, &val);
// fprintf(stdout, "SX1302_REG_CAPTURE_RAM_CAPTURE_PERIOD_0_CAPTUREPERIOD value: %d\n", val);
// lgw_reg_r(SX1302_REG_CAPTURE_RAM_CAPTURE_PERIOD_1_CAPTUREPERIOD, &val);
// fprintf(stdout, "SX1302_REG_CAPTURE_RAM_CAPTURE_PERIOD_1_CAPTUREPERIOD value: %d\n", val);
/* Launch capture */
lgw_reg_w(SX1302_REG_CAPTURE_RAM_CAPTURE_CFG_CAPTURESTART, 1);
// lgw_reg_w(SX1302_REG_CAPTURE_RAM_CAPTURE_CFG_CAPTUREFORCETRIGGER, 1);
/* Poll Status.CapComplete */
do{
lgw_reg_r(SX1302_REG_CAPTURE_RAM_STATUS_CAPCOMPLETE, &val);
wait_ms(10);
if ((quit_sig == 1) || (exit_sig == 1)) {
break;
}
} while (val != 1);
lgw_reg_w(SX1302_REG_CAPTURE_RAM_CAPTURE_CFG_CAPTURESTART, 0);
// lgw_reg_r(SX1302_REG_CAPTURE_RAM_LAST_RAM_ADDR_0_LASTRAMADDR, &val);
// fprintf(stdout, "SX1302_REG_CAPTURE_RAM_LAST_RAM_ADDR_0_LASTRAMADDR value: %02x\n", val);
// lgw_reg_r(SX1302_REG_CAPTURE_RAM_LAST_RAM_ADDR_1_LASTRAMADDR, &val);
// fprintf(stdout, "SX1302_REG_CAPTURE_RAM_LAST_RAM_ADDR_1_LASTRAMADDR value: %02x\n", val);
lgw_reg_w(SX1302_REG_COMMON_PAGE_PAGE, 1);
lgw_mem_rb(0, capture_ram_buffer, CAPTURE_RAM_SIZE, false);
lgw_reg_w(SX1302_REG_COMMON_PAGE_PAGE, 0);
printf("Data:\n");
for (i = 0; i < CAPTURE_RAM_SIZE; i += 4)
{
if (((capture_source >= 2) && (capture_source <= 3)) || (capture_source == 9))
{
real = (int16_t)((((uint16_t)(capture_ram_buffer[i+3]) << 8) & 0xFF00) + ((uint16_t)capture_ram_buffer[i+2] & 0x00FF));
imag = (int16_t)((((uint16_t)(capture_ram_buffer[i+1]) << 8) & 0xFF00) + ((uint16_t)capture_ram_buffer[i+0] & 0x00FF));
real >>= 4; // 12 bits I
imag >>= 4; // 12 bits Q
}
else if ((capture_source >= 4) && (capture_source <= 6))
{
real = (int16_t)((((uint16_t)(capture_ram_buffer[i+3]) << 8) & 0xFF00) + ((uint16_t)capture_ram_buffer[i+2] & 0x00FF)); // 16 bits I
imag = (int16_t)((((uint16_t)(capture_ram_buffer[i+1]) << 8) & 0xFF00) + ((uint16_t)capture_ram_buffer[i+0] & 0x00FF)); // 16 bits Q
}
else if ((capture_source >= 10) && (capture_source <= 17))
{
real = (int8_t)(capture_ram_buffer[i+3]); // 8 bits I
imag = (int8_t)(capture_ram_buffer[i+1]); // 8 bits Q
}
else
{
real = 0;
imag = 0;
}
if (((capture_source >= 2) && (capture_source <= 6)) || ((capture_source >= 9) && (capture_source <= 17)))
{
fprintf(stdout, "%d", real);
if (imag >= 0)
{
fprintf(stdout, "+");
}
fprintf(stdout, "%di\n", imag);
}
else
{
printf("%02X ", capture_ram_buffer[i]);
}
}
printf("End of Data\n");
#if FULL_INIT
/* Board reset */
if (system("./reset_lgw.sh stop") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
#endif
return 0;
}

View file

@ -0,0 +1,257 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2019 Semtech
Description:
Minimum test program for HAL timestamp counter handling
License: Revised BSD License, see LICENSE.TXT file include in the project
*/
/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */
/* fix an issue between POSIX and C99 */
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <math.h>
#include "loragw_hal.h"
#include "loragw_reg.h"
#include "loragw_aux.h"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
#define LINUXDEV_PATH_DEFAULT "/dev/spidev0.0"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define RAND_RANGE(min, max) (rand() % (max + 1 - min) + min)
/* -------------------------------------------------------------------------- */
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
#define DEFAULT_FREQ_HZ 868500000U
/* -------------------------------------------------------------------------- */
/* --- PRIVATE VARIABLES ---------------------------------------------------- */
static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
/* -------------------------------------------------------------------------- */
/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
static void sig_handler(int sigio) {
if (sigio == SIGQUIT) {
quit_sig = 1;;
} else if ((sigio == SIGINT) || (sigio == SIGTERM)) {
exit_sig = 1;
}
}
void usage(void) {
//printf("Library version information: %s\n", lgw_version_info());
printf( "Available options:\n");
printf( " -h print this help\n");
printf( " -k <uint> Concentrator clock source (Radio A or Radio B) [0..1]\n");
printf( " -r <uint> Radio type (1255, 1257, 1250)\n");
printf( " -p Test PPS trig counter when set\n" );
}
/* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */
int main(int argc, char **argv)
{
/* SPI interfaces */
const char spidev_path_default[] = LINUXDEV_PATH_DEFAULT;
const char * spidev_path = spidev_path_default;
struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
int i, x;
uint32_t fa = DEFAULT_FREQ_HZ;
uint32_t fb = DEFAULT_FREQ_HZ;
unsigned int arg_u;
uint8_t clocksource = 0;
lgw_radio_type_t radio_type = LGW_RADIO_TYPE_NONE;
struct lgw_conf_board_s boardconf;
struct lgw_conf_rxrf_s rfconf;
struct lgw_conf_rxif_s ifconf;
uint32_t counter;
bool trig_cnt = false;
const int32_t channel_if[9] = {
-400000,
-200000,
0,
-400000,
-200000,
0,
200000,
400000,
-200000 /* lora service */
};
const uint8_t channel_rfchain[9] = { 1, 1, 1, 0, 0, 0, 0, 0, 1 };
/* parse command line options */
while ((i = getopt (argc, argv, "hk:r:p")) != -1) {
switch (i) {
case 'h':
usage();
return -1;
break;
case 'r': /* <uint> Radio type */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || ((arg_u != 1255) && (arg_u != 1257) && (arg_u != 1250))) {
printf("ERROR: argument parsing of -r argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
switch (arg_u) {
case 1255:
radio_type = LGW_RADIO_TYPE_SX1255;
break;
case 1257:
radio_type = LGW_RADIO_TYPE_SX1257;
break;
default: /* 1250 */
radio_type = LGW_RADIO_TYPE_SX1250;
break;
}
}
break;
case 'k': /* <uint> Clock Source */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 1)) {
printf("ERROR: argument parsing of -k argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
clocksource = (uint8_t)arg_u;
}
break;
case 'p':
trig_cnt = true;
break;
default:
printf("ERROR: argument parsing\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);
printf("===== sx1302 counter test =====\n");
/* Board reset */
if (system("./reset_lgw.sh start") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
/* Configure the gateway */
memset( &boardconf, 0, sizeof boardconf);
boardconf.lorawan_public = true;
boardconf.clksrc = clocksource;
boardconf.full_duplex = false;
strncpy(boardconf.spidev_path, spidev_path, sizeof boardconf.spidev_path);
if (lgw_board_setconf(&boardconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure board\n");
return EXIT_FAILURE;
}
/* set configuration for RF chains */
memset( &rfconf, 0, sizeof rfconf);
rfconf.enable = true;
rfconf.freq_hz = fa;
rfconf.type = radio_type;
rfconf.tx_enable = false;
if (lgw_rxrf_setconf(0, &rfconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxrf 0\n");
return EXIT_FAILURE;
}
memset( &rfconf, 0, sizeof rfconf);
rfconf.enable = true;
rfconf.freq_hz = fb;
rfconf.type = radio_type;
rfconf.tx_enable = false;
if (lgw_rxrf_setconf(1, &rfconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxrf 1\n");
return EXIT_FAILURE;
}
/* set configuration for LoRa multi-SF channels (bandwidth cannot be set) */
memset(&ifconf, 0, sizeof(ifconf));
for (i = 0; i < 9; i++) {
ifconf.enable = true;
ifconf.rf_chain = channel_rfchain[i];
ifconf.freq_hz = channel_if[i];
ifconf.datarate = DR_LORA_SF7;
if (lgw_rxif_setconf(i, &ifconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxif %d\n", i);
return EXIT_FAILURE;
}
}
/* connect, configure and start the LoRa concentrator */
x = lgw_start();
if (x != 0) {
printf("ERROR: failed to start the gateway\n");
return EXIT_FAILURE;
}
/* Loop until user quits */
while( (quit_sig != 1) && (exit_sig != 1) ) {
if (trig_cnt == false) {
lgw_get_instcnt(&counter);
} else {
lgw_get_trigcnt(&counter);
}
wait_ms(10);
}
/* Stop the gateway */
x = lgw_stop();
if (x != 0) {
printf("ERROR: failed to stop the gateway\n");
return EXIT_FAILURE;
}
/* Board reset */
if (system("./reset_lgw.sh stop") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
printf("=========== Test End ===========\n");
return 0;
}
/* --- EOF ------------------------------------------------------------------ */

View file

@ -0,0 +1,415 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2019 Semtech
Description:
Minimum test program for the loragw_gps module
License: Revised BSD License, see LICENSE.TXT file include in the project
*/
/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */
/* fix an issue between POSIX and C99 */
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif
#include <stdint.h> /* C99 types */
#include <stdbool.h> /* bool type */
#include <stdio.h> /* printf */
#include <string.h> /* memset */
#include <signal.h> /* sigaction */
#include <stdlib.h> /* exit */
#include <unistd.h> /* read */
#include "loragw_hal.h"
#include "loragw_gps.h"
#include "loragw_aux.h"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
#define MATCH(a,b) ( ((int32_t)(a-b)<=1) && ((int32_t)(a-b)>=-1) ) /* tolerate 1µs */
/* -------------------------------------------------------------------------- */
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
#define LINUXDEV_PATH_DEFAULT "/dev/spidev0.0"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE VARIABLES ---------------------------------------------------- */
static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
struct tref ppm_ref;
/* -------------------------------------------------------------------------- */
/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
static void sig_handler(int sigio);
static void gps_process_sync(void);
static void gps_process_coords(void);
/* -------------------------------------------------------------------------- */
/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
void usage(void) {
//printf("Library version information: %s\n", lgw_version_info());
printf( "Available options:\n");
printf( " -h print this help\n");
printf( " -k <uint> Concentrator clock source (Radio A or Radio B) [0..1]\n");
printf( " -r <uint> Radio type (1255, 1257, 1250)\n");
}
static void sig_handler(int sigio) {
if (sigio == SIGQUIT) {
quit_sig = 1;;
} else if ((sigio == SIGINT) || (sigio == SIGTERM)) {
exit_sig = 1;
}
}
static void gps_process_sync(void) {
/* variables for PPM pulse GPS synchronization */
uint32_t ppm_tstamp;
struct timespec ppm_gps;
struct timespec ppm_utc;
/* variables for timestamp <-> GPS time conversions */
uint32_t x, z;
struct timespec y;
/* get GPS time for synchronization */
int i = lgw_gps_get(&ppm_utc, &ppm_gps, NULL, NULL);
if (i != LGW_GPS_SUCCESS) {
printf(" No valid reference GPS time available, synchronization impossible.\n");
return;
}
/* get timestamp for synchronization */
i = lgw_get_trigcnt(&ppm_tstamp);
if (i != LGW_HAL_SUCCESS) {
printf(" Failed to read timestamp, synchronization impossible.\n");
return;
}
/* try to update synchronize time reference with the new GPS & timestamp */
i = lgw_gps_sync(&ppm_ref, ppm_tstamp, ppm_utc, ppm_gps);
if (i != LGW_GPS_SUCCESS) {
printf(" Synchronization error.\n");
return;
}
/* display result */
printf(" * Synchronization successful *\n");
printf(" UTC reference time: %lld.%09ld\n", (long long)ppm_ref.utc.tv_sec, ppm_ref.utc.tv_nsec);
printf(" GPS reference time: %lld.%09ld\n", (long long)ppm_ref.gps.tv_sec, ppm_ref.gps.tv_nsec);
printf(" Internal counter reference value: %u\n", ppm_ref.count_us);
printf(" Clock error: %.9f\n", ppm_ref.xtal_err);
x = ppm_tstamp + 500000;
/* CNT -> GPS -> CNT */
printf("\n");
printf(" * Test of timestamp counter <-> GPS value conversion *\n");
printf(" Test value: %u\n", x);
lgw_cnt2gps(ppm_ref, x, &y);
printf(" Conversion to GPS: %lld.%09ld\n", (long long)y.tv_sec, y.tv_nsec);
lgw_gps2cnt(ppm_ref, y, &z);
printf(" Converted back: %u ==> %dµs\n", z, (int32_t)(z-x));
/* Display test result */
if (MATCH(x,z)) {
printf(" ** PASS **: (SX1302 -> GPS -> SX1302) conversion MATCH\n");
} else {
printf(" ** FAILED **: (SX1302 -> GPS -> SX1302) conversion MISMATCH\n");
}
/* CNT -> UTC -> CNT */
printf("\n");
printf(" * Test of timestamp counter <-> UTC value conversion *\n");
printf(" Test value: %u\n", x);
lgw_cnt2utc(ppm_ref, x, &y);
printf(" Conversion to UTC: %lld.%09ld\n", (long long)y.tv_sec, y.tv_nsec);
lgw_utc2cnt(ppm_ref, y, &z);
printf(" Converted back: %u ==> %dµs\n", z, (int32_t)(z-x));
/* Display test result */
if (MATCH(x,z)) {
printf(" ** PASS **: (SX1302 -> UTC -> SX1302) conversion MATCH\n");
} else {
printf(" ** FAILED **: (SX1302 -> UTC -> SX1302) conversion MISMATCH\n");
}
}
static void gps_process_coords(void) {
/* position variable */
struct coord_s coord;
struct coord_s gpserr;
int i = lgw_gps_get(NULL, NULL, &coord, &gpserr);
/* update gateway coordinates */
if (i == LGW_GPS_SUCCESS) {
printf("\n");
printf("# GPS coordinates: latitude %.5f, longitude %.5f, altitude %i m\n", coord.lat, coord.lon, coord.alt);
printf("# GPS err: latitude %.5f, longitude %.5f, altitude %i m\n", gpserr.lat, gpserr.lon, gpserr.alt);
}
}
/* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */
int main(int argc, char **argv)
{
/* SPI interfaces */
const char spidev_path_default[] = LINUXDEV_PATH_DEFAULT;
const char * spidev_path = spidev_path_default;
struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
int i;
unsigned int arg_u;
/* concentrator variables */
uint8_t clocksource = 0;
lgw_radio_type_t radio_type = LGW_RADIO_TYPE_NONE;
struct lgw_conf_board_s boardconf;
struct lgw_conf_rxrf_s rfconf;
/* serial variables */
char serial_buff[128]; /* buffer to receive GPS data */
size_t wr_idx = 0; /* pointer to end of chars in buffer */
int gps_tty_dev; /* file descriptor to the serial port of the GNSS module */
/* NMEA/UBX variables */
enum gps_msg latest_msg; /* keep track of latest NMEA/UBX message parsed */
/* parse command line options */
while ((i = getopt (argc, argv, "hk:r:")) != -1) {
switch (i) {
case 'h':
usage();
return -1;
break;
case 'r': /* <uint> Radio type */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || ((arg_u != 1255) && (arg_u != 1257) && (arg_u != 1250))) {
printf("ERROR: argument parsing of -r argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
switch (arg_u) {
case 1255:
radio_type = LGW_RADIO_TYPE_SX1255;
break;
case 1257:
radio_type = LGW_RADIO_TYPE_SX1257;
break;
default: /* 1250 */
radio_type = LGW_RADIO_TYPE_SX1250;
break;
}
}
break;
case 'k': /* <uint> Clock Source */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 1)) {
printf("ERROR: argument parsing of -k argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
clocksource = (uint8_t)arg_u;
}
break;
default:
printf("ERROR: argument parsing\n");
usage();
exit(EXIT_FAILURE);
}
}
/* Check arguments */
if (radio_type == LGW_RADIO_TYPE_NONE) {
printf("ERROR: radio type must be specified\n");
usage();
exit(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);
/* Intro message and library information */
printf("Beginning of test for loragw_gps.c\n");
printf("*** Library version information ***\n%s\n***\n", lgw_version_info());
/* Board reset */
if (system("./reset_lgw.sh start") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
/* Open and configure GPS */
i = lgw_gps_enable("/dev/ttyS0", "ubx7", 0, &gps_tty_dev);
if (i != LGW_GPS_SUCCESS) {
printf("ERROR: Failed to enable GPS\n");
exit(EXIT_FAILURE);
}
/* start concentrator (default conf for IoT SK) */
/* board config */
memset(&boardconf, 0, sizeof(boardconf));
boardconf.lorawan_public = true;
boardconf.clksrc = clocksource;
boardconf.full_duplex = false;
strncpy(boardconf.spidev_path, spidev_path, sizeof boardconf.spidev_path);
if (lgw_board_setconf(&boardconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure board\n");
return EXIT_FAILURE;
}
/* set configuration for RF chains */
memset( &rfconf, 0, sizeof rfconf);
rfconf.enable = true;
rfconf.freq_hz = 868000000;
rfconf.rssi_offset = 0.0;
rfconf.type = radio_type;
rfconf.tx_enable = false;
if (lgw_rxrf_setconf(0, &rfconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxrf 0\n");
return EXIT_FAILURE;
}
memset( &rfconf, 0, sizeof rfconf);
rfconf.enable = true;
rfconf.freq_hz = 868000000;
rfconf.rssi_offset = 0.0;
rfconf.type = radio_type;
rfconf.tx_enable = false;
if (lgw_rxrf_setconf(1, &rfconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxrf 1\n");
return EXIT_FAILURE;
}
/* start */
if (lgw_start() != LGW_HAL_SUCCESS) {
printf("ERROR: IMPOSSIBLE TO START THE GATEWAY\n");
exit(EXIT_FAILURE);
}
/* initialize some variables before loop */
memset(serial_buff, 0, sizeof serial_buff);
memset(&ppm_ref, 0, sizeof ppm_ref);
/* loop until user action */
while ((quit_sig != 1) && (exit_sig != 1)) {
size_t rd_idx = 0;
size_t frame_end_idx = 0;
/* blocking non-canonical read on serial port */
ssize_t nb_char = read(gps_tty_dev, serial_buff + wr_idx, LGW_GPS_MIN_MSG_SIZE);
if (nb_char <= 0) {
printf("WARNING: [gps] read() returned value %d\n", nb_char);
continue;
}
wr_idx += (size_t)nb_char;
/*******************************************
* Scan buffer for UBX/NMEA sync chars and *
* attempt to decode frame if one is found *
*******************************************/
while (rd_idx < wr_idx) {
size_t frame_size = 0;
/* Scan buffer for UBX sync char */
if (serial_buff[rd_idx] == LGW_GPS_UBX_SYNC_CHAR) {
/***********************
* Found UBX sync char *
***********************/
latest_msg = lgw_parse_ubx(&serial_buff[rd_idx], (wr_idx - rd_idx), &frame_size);
if (frame_size > 0) {
if (latest_msg == INCOMPLETE) {
/* UBX header found but frame appears to be missing bytes */
frame_size = 0;
} else if (latest_msg == INVALID) {
/* message header received but message appears to be corrupted */
printf("WARNING: [gps] could not get a valid message from GPS (no time)\n");
frame_size = 0;
} else if (latest_msg == UBX_NAV_TIMEGPS) {
printf("\n~~ UBX NAV-TIMEGPS sentence, triggering synchronization attempt ~~\n");
gps_process_sync();
}
}
} else if(serial_buff[rd_idx] == LGW_GPS_NMEA_SYNC_CHAR) {
/************************
* Found NMEA sync char *
************************/
/* scan for NMEA end marker (LF = 0x0a) */
char* nmea_end_ptr = memchr(&serial_buff[rd_idx],(int)0x0a, (wr_idx - rd_idx));
if (nmea_end_ptr) {
/* found end marker */
frame_size = nmea_end_ptr - &serial_buff[rd_idx] + 1;
latest_msg = lgw_parse_nmea(&serial_buff[rd_idx], frame_size);
if(latest_msg == INVALID || latest_msg == UNKNOWN) {
/* checksum failed */
frame_size = 0;
} else if (latest_msg == NMEA_RMC) { /* Get location from RMC frames */
gps_process_coords();
}
}
}
if (frame_size > 0) {
/* At this point message is a checksum verified frame
we're processed or ignored. Remove frame from buffer */
rd_idx += frame_size;
frame_end_idx = rd_idx;
} else {
rd_idx++;
}
} /* ...for(rd_idx = 0... */
if (frame_end_idx) {
/* Frames have been processed. Remove bytes to end of last processed frame */
memcpy(serial_buff,&serial_buff[frame_end_idx],wr_idx - frame_end_idx);
wr_idx -= frame_end_idx;
} /* ...for(rd_idx = 0... */
/* Prevent buffer overflow */
if ((sizeof(serial_buff) - wr_idx) < LGW_GPS_MIN_MSG_SIZE) {
memcpy(serial_buff,&serial_buff[LGW_GPS_MIN_MSG_SIZE],wr_idx - LGW_GPS_MIN_MSG_SIZE);
wr_idx -= LGW_GPS_MIN_MSG_SIZE;
}
}
/* clean up before leaving */
if (exit_sig == 1) {
lgw_gps_disable(gps_tty_dev);
lgw_stop();
}
/* Board reset */
if (system("./reset_lgw.sh stop") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
printf("\nEnd of test for loragw_gps.c\n");
exit(EXIT_SUCCESS);
}
/* --- EOF ------------------------------------------------------------------ */

View file

@ -0,0 +1,320 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2019 Semtech
Description:
Minimum test program for HAL RX capability
License: Revised BSD License, see LICENSE.TXT file include in the project
*/
/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */
/* fix an issue between POSIX and C99 */
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <math.h>
#include "loragw_hal.h"
#include "loragw_reg.h"
#include "loragw_aux.h"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
#define LINUXDEV_PATH_DEFAULT "/dev/spidev0.0"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define RAND_RANGE(min, max) (rand() % (max + 1 - min) + min)
/* -------------------------------------------------------------------------- */
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
#define DEFAULT_FREQ_HZ 868500000U
/* -------------------------------------------------------------------------- */
/* --- PRIVATE VARIABLES ---------------------------------------------------- */
static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
/* -------------------------------------------------------------------------- */
/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
static void sig_handler(int sigio) {
if (sigio == SIGQUIT) {
quit_sig = 1;
} else if ((sigio == SIGINT) || (sigio == SIGTERM)) {
exit_sig = 1;
}
}
void usage(void) {
//printf("Library version information: %s\n", lgw_version_info());
printf( "Available options:\n");
printf( " -h print this help\n");
printf( " -k <uint> Concentrator clock source (Radio A or Radio B) [0..1]\n");
printf( " -r <uint> Radio type (1255, 1257, 1250)\n");
printf( " -a <float> Radio A RX frequency in MHz\n");
printf( " -b <float> Radio B RX frequency in MHz\n");
printf( " -n <uint> number of packet received with CRC OK for each HAL start/stop loop\n");
}
/* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */
int main(int argc, char **argv)
{
/* SPI interfaces */
const char spidev_path_default[] = LINUXDEV_PATH_DEFAULT;
const char * spidev_path = spidev_path_default;
struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
int i, j, x;
uint32_t fa = DEFAULT_FREQ_HZ;
uint32_t fb = DEFAULT_FREQ_HZ;
double arg_d = 0.0;
unsigned int arg_u;
uint8_t clocksource = 0;
lgw_radio_type_t radio_type = LGW_RADIO_TYPE_NONE;
struct lgw_conf_board_s boardconf;
struct lgw_conf_rxrf_s rfconf;
struct lgw_conf_rxif_s ifconf;
struct lgw_pkt_rx_s rxpkt[16];
unsigned long nb_pkt_crc_ok = 0, nb_loop = 1, cnt_loop;
int nb_pkt;
const int32_t channel_if[9] = {
-400000,
-200000,
0,
-400000,
-200000,
0,
200000,
400000,
-200000 /* lora service */
};
const uint8_t channel_rfchain[9] = { 1, 1, 1, 0, 0, 0, 0, 0, 1 };
/* parse command line options */
while ((i = getopt (argc, argv, "ha:b:k:r:n:")) != -1) {
switch (i) {
case 'h':
usage();
return -1;
break;
case 'r': /* <uint> Radio type */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || ((arg_u != 1255) && (arg_u != 1257) && (arg_u != 1250))) {
printf("ERROR: argument parsing of -r argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
switch (arg_u) {
case 1255:
radio_type = LGW_RADIO_TYPE_SX1255;
break;
case 1257:
radio_type = LGW_RADIO_TYPE_SX1257;
break;
default: /* 1250 */
radio_type = LGW_RADIO_TYPE_SX1250;
break;
}
}
break;
case 'k': /* <uint> Clock Source */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 1)) {
printf("ERROR: argument parsing of -k argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
clocksource = (uint8_t)arg_u;
}
break;
case 'a': /* <float> Radio A RX frequency in MHz */
i = sscanf(optarg, "%lf", &arg_d);
if (i != 1) {
printf("ERROR: argument parsing of -f argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
fa = (uint32_t)((arg_d*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
}
break;
case 'b': /* <float> Radio B RX frequency in MHz */
i = sscanf(optarg, "%lf", &arg_d);
if (i != 1) {
printf("ERROR: argument parsing of -f argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
fb = (uint32_t)((arg_d*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
}
break;
case 'n': /* <uint> NUmber of packets to be received before exiting */
i = sscanf(optarg, "%u", &arg_u);
if (i != 1) {
printf("ERROR: argument parsing of -n argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
nb_loop = arg_u;
}
break;
default:
printf("ERROR: argument parsing\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);
printf("===== sx1302 HAL RX test =====\n");
/* Configure the gateway */
memset( &boardconf, 0, sizeof boardconf);
boardconf.lorawan_public = true;
boardconf.clksrc = clocksource;
boardconf.full_duplex = false;
strncpy(boardconf.spidev_path, spidev_path, sizeof boardconf.spidev_path);
if (lgw_board_setconf(&boardconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure board\n");
return EXIT_FAILURE;
}
/* set configuration for RF chains */
memset( &rfconf, 0, sizeof rfconf);
rfconf.enable = true;
rfconf.freq_hz = fa;
rfconf.type = radio_type;
rfconf.tx_enable = false;
if (lgw_rxrf_setconf(0, &rfconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxrf 0\n");
return EXIT_FAILURE;
}
memset( &rfconf, 0, sizeof rfconf);
rfconf.enable = true;
rfconf.freq_hz = fb;
rfconf.type = radio_type;
rfconf.tx_enable = false;
if (lgw_rxrf_setconf(1, &rfconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxrf 1\n");
return EXIT_FAILURE;
}
/* set configuration for LoRa multi-SF channels (bandwidth cannot be set) */
memset(&ifconf, 0, sizeof(ifconf));
for (i = 0; i < 9; i++) {
ifconf.enable = true;
ifconf.rf_chain = channel_rfchain[i];
ifconf.freq_hz = channel_if[i];
ifconf.datarate = DR_LORA_SF7;
if (lgw_rxif_setconf(i, &ifconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxif %d\n", i);
return EXIT_FAILURE;
}
}
/* Loop until user quits */
cnt_loop = 0;
while( (quit_sig != 1) && (exit_sig != 1) )
{
cnt_loop += 1;
/* Board reset */
if (system("./reset_lgw.sh start") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
/* connect, configure and start the LoRa concentrator */
x = lgw_start();
if (x != 0) {
printf("ERROR: failed to start the gateway\n");
return EXIT_FAILURE;
}
/* Loop until we have enough packets with CRC OK */
printf("Waiting for packets...\n");
nb_pkt_crc_ok = 0;
while ((nb_pkt_crc_ok < nb_loop) && (quit_sig != 1) && (exit_sig != 1)) {
/* fetch N packets */
nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt);
if (nb_pkt == 0) {
wait_ms(10);
} else {
printf("Received %d packets\n", nb_pkt);
for (i = 0; i < nb_pkt; i++) {
if (rxpkt[i].status == STAT_CRC_OK) {
nb_pkt_crc_ok += 1;
}
printf("\n----- %s packet -----\n", (rxpkt[i].modulation == MOD_LORA) ? "LoRa" : "FSK");
printf(" count_us: %u\n", rxpkt[i].count_us);
printf(" size: %u\n", rxpkt[i].size);
printf(" chan: %u\n", rxpkt[i].if_chain);
printf(" status: 0x%02X\n", rxpkt[i].status);
printf(" datr: %u\n", rxpkt[i].datarate);
printf(" codr: %u\n", rxpkt[i].coderate);
printf(" rf_chain %u\n", rxpkt[i].rf_chain);
printf(" freq_hz %u\n", rxpkt[i].freq_hz);
printf(" snr_avg: %.1f\n", rxpkt[i].snr);
printf(" rssi_chan:%.1f\n", rxpkt[i].rssic);
printf(" rssi_sig :%.1f\n", rxpkt[i].rssis);
printf(" crc: 0x%04X\n", rxpkt[i].crc);
for (j = 0; j < rxpkt[i].size; j++) {
printf("%02X ", rxpkt[i].payload[j]);
}
printf("\n");
}
}
}
printf( "\nNb valid packets received: %lu CRC OK (%lu)\n", nb_pkt_crc_ok, cnt_loop );
/* Stop the gateway */
x = lgw_stop();
if (x != 0) {
printf("ERROR: failed to stop the gateway\n");
return EXIT_FAILURE;
}
/* Board reset */
if (system("./reset_lgw.sh stop") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
}
printf("=========== Test End ===========\n");
return 0;
}
/* --- EOF ------------------------------------------------------------------ */

View file

@ -0,0 +1,583 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2019 Semtech
Description:
Minimum test program for HAL TX capability
License: Revised BSD License, see LICENSE.TXT file include in the project
*/
/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */
/* fix an issue between POSIX and C99 */
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <signal.h> /* sigaction */
#include <getopt.h> /* getopt_long */
#include "loragw_hal.h"
#include "loragw_reg.h"
#include "loragw_aux.h"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
#define RAND_RANGE(min, max) (rand() % (max + 1 - min) + min)
/* -------------------------------------------------------------------------- */
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
#define LINUXDEV_PATH_DEFAULT "/dev/spidev0.0"
#define DEFAULT_CLK_SRC 0
#define DEFAULT_FREQ_HZ 868500000U
/* -------------------------------------------------------------------------- */
/* --- PRIVATE VARIABLES ---------------------------------------------------- */
/* Signal handling variables */
static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
/* -------------------------------------------------------------------------- */
/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
/* describe command line options */
void usage(void) {
//printf("Library version information: %s\n", lgw_version_info());
printf("Available options:\n");
printf(" -h print this help\n");
printf(" -k <uint> Concentrator clock source (Radio A or Radio B) [0..1]\n");
printf(" -c <uint> RF chain to be used for TX (Radio A or Radio B) [0..1]\n");
printf(" -r <uint> Radio type (1255, 1257, 1250)\n");
printf(" -f <float> Radio TX frequency in MHz\n");
printf(" -m <str> modulation type ['CW', 'LORA', 'FSK']\n");
printf(" -o <int> CW frequency offset from Radio TX frequency in kHz [-65..65]\n");
printf(" -s <uint> LoRa datarate 0:random, [5..12]\n");
printf(" -b <uint> LoRa bandwidth in khz 0:random, [125, 250, 500]\n");
printf(" -l <uint> FSK/LoRa preamble length, [6..65535]\n");
printf(" -d <uint> FSK frequency deviation in kHz [1:250]\n");
printf(" -q <float> FSK bitrate in kbps [0.5:250]\n");
printf(" -n <uint> Number of packets to be sent\n");
printf(" -z <uint> size of packets to be sent 0:random, [9..255]\n");
printf(" -t <uint> TX mode timestamped with delay in ms. If delay is 0, TX mode GPS trigger\n");
printf(" -p <int> RF power in dBm\n");
printf(" -i Send LoRa packet using inverted modulation polarity\n");
printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
printf(" --pa <uint> PA gain SX125x:[0..3], SX1250:[0,1]\n");
printf(" --dig <uint> sx1302 digital gain for sx125x [0..3]\n");
printf(" --dac <uint> sx125x DAC gain [0..3]\n");
printf(" --mix <uint> sx125x MIX gain [5..15]\n");
printf(" --pwid <uint> sx1250 power index [0..22]\n");
printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
printf(" --nhdr Send LoRa packet with implicit header\n");
printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
printf(" --loop Number of loops for HAL start/stop (HAL unitary test)\n");
}
/* handle signals */
static void sig_handler(int sigio)
{
if (sigio == SIGQUIT) {
quit_sig = 1;
}
else if((sigio == SIGINT) || (sigio == SIGTERM)) {
exit_sig = 1;
}
}
/* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */
int main(int argc, char **argv)
{
int i, x;
uint32_t ft = DEFAULT_FREQ_HZ;
int8_t rf_power = 0;
uint8_t sf = 0;
uint16_t bw_khz = 0;
uint32_t nb_pkt = 1;
unsigned int nb_loop = 1, cnt_loop;
uint8_t size = 0;
char mod[64] = "LORA";
float br_kbps = 50;
uint8_t fdev_khz = 25;
int8_t freq_offset = 0;
double arg_d = 0.0;
unsigned int arg_u;
int arg_i;
char arg_s[64];
float xf = 0.0;
uint8_t clocksource = 0;
uint8_t rf_chain = 0;
lgw_radio_type_t radio_type = LGW_RADIO_TYPE_NONE;
uint16_t preamble = 8;
bool invert_pol = false;
bool no_header = false;
struct lgw_conf_board_s boardconf;
struct lgw_conf_rxrf_s rfconf;
struct lgw_pkt_tx_s pkt;
struct lgw_tx_gain_lut_s txlut; /* TX gain table */
uint8_t tx_status;
uint32_t count_us;
uint32_t trig_delay_us = 1000000;
bool trig_delay = false;
/* SPI interfaces */
const char spidev_path_default[] = LINUXDEV_PATH_DEFAULT;
const char * spidev_path = spidev_path_default;
static struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
/* Initialize TX gain LUT */
txlut.size = 0;
memset(txlut.lut, 0, sizeof txlut.lut);
/* Parameter parsing */
int option_index = 0;
static struct option long_options[] = {
{"pa", required_argument, 0, 0},
{"dac", required_argument, 0, 0},
{"dig", required_argument, 0, 0},
{"mix", required_argument, 0, 0},
{"pwid", required_argument, 0, 0},
{"loop", required_argument, 0, 0},
{"nhdr", no_argument, 0, 0},
{0, 0, 0, 0}
};
/* parse command line options */
while ((i = getopt_long (argc, argv, "hif:s:b:n:z:p:k:r:c:l:t:m:o:q:d:", long_options, &option_index)) != -1) {
switch (i) {
case 'h':
usage();
return -1;
break;
case 'i': /* Send packet using inverted modulation polarity */
invert_pol = true;
break;
case 'r': /* <uint> Radio type */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || ((arg_u != 1255) && (arg_u != 1257) && (arg_u != 1250))) {
printf("ERROR: argument parsing of -r argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
switch (arg_u) {
case 1255:
radio_type = LGW_RADIO_TYPE_SX1255;
break;
case 1257:
radio_type = LGW_RADIO_TYPE_SX1257;
break;
default: /* 1250 */
radio_type = LGW_RADIO_TYPE_SX1250;
break;
}
}
break;
case 'l': /* <uint> LoRa/FSK preamble length */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 65535)) {
printf("ERROR: argument parsing of -l argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
preamble = (uint16_t)arg_u;
}
break;
case 'm': /* <str> Modulation type */
i = sscanf(optarg, "%s", arg_s);
if ((i != 1) || ((strcmp(arg_s, "CW") != 0) && (strcmp(arg_s, "LORA") != 0) && (strcmp(arg_s, "FSK")))) {
printf("ERROR: invalid modulation type\n");
return EXIT_FAILURE;
} else {
sprintf(mod, "%s", arg_s);
}
break;
case 'o': /* <int> CW frequency offset from Radio TX frequency */
i = sscanf(optarg, "%d", &arg_i);
if ((arg_i < -65) || (arg_i > 65)) {
printf("ERROR: invalid frequency offset\n");
return EXIT_FAILURE;
} else {
freq_offset = (int32_t)arg_i;
}
break;
case 'd': /* <uint> FSK frequency deviation */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u < 1) || (arg_u > 250)) {
printf("ERROR: invalid FSK frequency deviation\n");
return EXIT_FAILURE;
} else {
fdev_khz = (uint8_t)arg_u;
}
break;
case 'q': /* <float> FSK bitrate */
i = sscanf(optarg, "%f", &xf);
if ((i != 1) || (xf < 0.5) || (xf > 250)) {
printf("ERROR: invalid FSK bitrate\n");
return EXIT_FAILURE;
} else {
br_kbps = xf;
}
break;
case 't': /* <uint> Trigger delay in ms */
i = sscanf(optarg, "%u", &arg_u);
if (i != 1) {
printf("ERROR: argument parsing of -t argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
trig_delay = true;
trig_delay_us = (uint32_t)(arg_u * 1E3);
}
break;
case 'k': /* <uint> Clock Source */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 1)) {
printf("ERROR: argument parsing of -k argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
clocksource = (uint8_t)arg_u;
}
break;
case 'c': /* <uint> RF chain */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 1)) {
printf("ERROR: argument parsing of -c argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
rf_chain = (uint8_t)arg_u;
}
break;
case 'f': /* <float> Radio TX frequency in MHz */
i = sscanf(optarg, "%lf", &arg_d);
if (i != 1) {
printf("ERROR: argument parsing of -f argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
ft = (uint32_t)((arg_d*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
}
break;
case 's': /* <uint> LoRa datarate */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u < 5) || (arg_u > 12)) {
printf("ERROR: argument parsing of -s argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
sf = (uint8_t)arg_u;
}
break;
case 'b': /* <uint> LoRa bandwidth in khz */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || ((arg_u != 125) && (arg_u != 250) && (arg_u != 500))) {
printf("ERROR: argument parsing of -b argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
bw_khz = (uint16_t)arg_u;
}
break;
case 'n': /* <uint> Number of packets to be sent */
i = sscanf(optarg, "%u", &arg_u);
if (i != 1) {
printf("ERROR: argument parsing of -n argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
nb_pkt = (uint32_t)arg_u;
}
break;
case 'p': /* <int> RF power */
i = sscanf(optarg, "%d", &arg_i);
if (i != 1) {
printf("ERROR: argument parsing of -p argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
rf_power = (int8_t)arg_i;
txlut.size = 1;
txlut.lut[0].rf_power = rf_power;
}
break;
case 'z': /* <uint> packet size */
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u < 9) || (arg_u > 255)) {
printf("ERROR: argument parsing of -z argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
size = (uint8_t)arg_u;
}
break;
case 0:
if (strcmp(long_options[option_index].name, "pa") == 0) {
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 3)) {
printf("ERROR: argument parsing of --pa argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
txlut.size = 1;
txlut.lut[0].pa_gain = (uint8_t)arg_u;
}
} else if (strcmp(long_options[option_index].name, "dac") == 0) {
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 3)) {
printf("ERROR: argument parsing of --dac argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
txlut.size = 1;
txlut.lut[0].dac_gain = (uint8_t)arg_u;
}
} else if (strcmp(long_options[option_index].name, "mix") == 0) {
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 15)) {
printf("ERROR: argument parsing of --mix argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
txlut.size = 1;
txlut.lut[0].mix_gain = (uint8_t)arg_u;
}
} else if (strcmp(long_options[option_index].name, "dig") == 0) {
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 3)) {
printf("ERROR: argument parsing of --dig argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
txlut.size = 1;
txlut.lut[0].dig_gain = (uint8_t)arg_u;
}
} else if (strcmp(long_options[option_index].name, "pwid") == 0) {
i = sscanf(optarg, "%u", &arg_u);
if ((i != 1) || (arg_u > 22)) {
printf("ERROR: argument parsing of --pwid argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
txlut.size = 1;
txlut.lut[0].mix_gain = 5; /* TODO: rework this, should not be needed for sx1250 */
txlut.lut[0].pwr_idx = (uint8_t)arg_u;
}
} else if (strcmp(long_options[option_index].name, "loop") == 0) {
printf("%p\n", optarg);
i = sscanf(optarg, "%u", &arg_u);
if (i != 1) {
printf("ERROR: argument parsing of --loop argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
nb_loop = arg_u;
}
} else if (strcmp(long_options[option_index].name, "nhdr") == 0) {
no_header = true;
} else {
printf("ERROR: argument parsing options. Use -h to print help\n");
return EXIT_FAILURE;
}
break;
default:
printf("ERROR: argument parsing\n");
usage();
return -1;
}
}
/* Summary of packet parameters */
if (strcmp(mod, "CW") == 0) {
printf("Sending %i CW on %u Hz (Freq. offset %d kHz) at %i dBm\n", nb_pkt, ft, freq_offset, rf_power);
}
else if (strcmp(mod, "FSK") == 0) {
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);
} else {
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);
}
/* 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 );
/* Configure the gateway */
memset( &boardconf, 0, sizeof boardconf);
boardconf.lorawan_public = true;
boardconf.clksrc = clocksource;
boardconf.full_duplex = false;
strncpy(boardconf.spidev_path, spidev_path, sizeof boardconf.spidev_path);
if (lgw_board_setconf(&boardconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure board\n");
return EXIT_FAILURE;
}
memset( &rfconf, 0, sizeof rfconf);
rfconf.enable = true; /* rf chain 0 needs to be enabled for calibration to work on sx1257 */
rfconf.freq_hz = 868500000; /* dummy */
rfconf.type = radio_type;
rfconf.tx_enable = true;
if (lgw_rxrf_setconf(0, &rfconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxrf 0\n");
return EXIT_FAILURE;
}
memset( &rfconf, 0, sizeof rfconf);
rfconf.enable = (((rf_chain == 1) || (clocksource == 1)) ? true : false);
rfconf.freq_hz = 868500000; /* dummy */
rfconf.type = radio_type;
rfconf.tx_enable = false;
if (lgw_rxrf_setconf(1, &rfconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxrf 1\n");
return EXIT_FAILURE;
}
if (txlut.size > 0) {
if (lgw_txgain_setconf(rf_chain, &txlut) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure txgain lut\n");
return EXIT_FAILURE;
}
}
for (cnt_loop = 0; cnt_loop < nb_loop; cnt_loop++) {
/* Board reset */
if (system("./reset_lgw.sh start") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
/* connect, configure and start the LoRa concentrator */
x = lgw_start();
if (x != 0) {
printf("ERROR: failed to start the gateway\n");
return EXIT_FAILURE;
}
/* Send packets */
memset(&pkt, 0, sizeof pkt);
pkt.rf_chain = rf_chain;
pkt.freq_hz = ft;
pkt.rf_power = rf_power;
if (trig_delay == false) {
pkt.tx_mode = IMMEDIATE;
} else {
if (trig_delay_us == 0) {
pkt.tx_mode = ON_GPS;
} else {
pkt.tx_mode = TIMESTAMPED;
}
}
if ( strcmp( mod, "CW" ) == 0 ) {
pkt.modulation = MOD_CW;
pkt.freq_offset = freq_offset;
pkt.f_dev = fdev_khz;
}
else if( strcmp( mod, "FSK" ) == 0 ) {
pkt.modulation = MOD_FSK;
pkt.no_crc = false;
pkt.datarate = br_kbps * 1e3;
pkt.f_dev = fdev_khz;
} else {
pkt.modulation = MOD_LORA;
pkt.coderate = CR_LORA_4_5;
pkt.no_crc = true;
}
pkt.invert_pol = invert_pol;
pkt.preamble = preamble;
pkt.no_header = no_header;
pkt.payload[0] = 0x40; /* Confirmed Data Up */
pkt.payload[1] = 0xAB;
pkt.payload[2] = 0xAB;
pkt.payload[3] = 0xAB;
pkt.payload[4] = 0xAB;
pkt.payload[5] = 0x00; /* FCTrl */
pkt.payload[6] = 0; /* FCnt */
pkt.payload[7] = 0; /* FCnt */
pkt.payload[8] = 0x02; /* FPort */
for (i = 9; i < 255; i++) {
pkt.payload[i] = i;
}
for (i = 0; i < (int)nb_pkt; i++) {
if (trig_delay == true) {
if (trig_delay_us > 0) {
lgw_get_instcnt(&count_us);
printf("count_us:%u\n", count_us);
pkt.count_us = count_us + trig_delay_us;
printf("programming TX for %u\n", pkt.count_us);
} else {
printf("programming TX for next PPS (GPS)\n");
}
}
if( strcmp( mod, "LORA" ) == 0 ) {
pkt.datarate = (sf == 0) ? (uint8_t)RAND_RANGE(5, 12) : sf;
}
switch (bw_khz) {
case 125:
pkt.bandwidth = BW_125KHZ;
break;
case 250:
pkt.bandwidth = BW_250KHZ;
break;
case 500:
pkt.bandwidth = BW_500KHZ;
break;
default:
pkt.bandwidth = (uint8_t)RAND_RANGE(BW_125KHZ, BW_500KHZ);
break;
}
pkt.size = (size == 0) ? (uint8_t)RAND_RANGE(9, 255) : size;
pkt.payload[6] = (uint8_t)(i >> 0); /* FCnt */
pkt.payload[7] = (uint8_t)(i >> 8); /* FCnt */
x = lgw_send(&pkt);
if (x != 0) {
printf("ERROR: failed to send packet\n");
return EXIT_FAILURE;
}
/* wait for packet to finish sending */
do {
wait_ms(5);
lgw_status(pkt.rf_chain, TX_STATUS, &tx_status); /* get TX status */
} while ((tx_status != TX_FREE) && (quit_sig != 1) && (exit_sig != 1));
if ((quit_sig == 1) || (exit_sig == 1)) {
break;
}
printf("TX done\n");
}
printf( "\nNb packets sent: %u (%u)\n", i, cnt_loop + 1 );
/* Stop the gateway */
x = lgw_stop();
if (x != 0) {
printf("ERROR: failed to stop the gateway\n");
return EXIT_FAILURE;
}
/* Board reset */
if (system("./reset_lgw.sh stop") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
}
printf("=========== Test End ===========\n");
return 0;
}
/* --- EOF ------------------------------------------------------------------ */

View file

@ -0,0 +1,245 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2019 Semtech
Description:
Minimum test program for the loragw_i2c module
License: Revised BSD License, see LICENSE.TXT file include in the project
*/
/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */
/* Fix an issue between POSIX and C99 */
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h> /* sigaction */
#include <unistd.h> /* getopt, access */
#include <time.h>
#include "loragw_i2c.h"
#include "loragw_aux.h"
#include "loragw_hal.h"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
#define I2C_PORT_STTS751 0x39
#define STTS751_REG_TEMP_H 0x00
#define STTS751_REG_TEMP_L 0x02
#define STTS751_REG_CONF 0x03
#define STTS751_REG_RATE 0x04
#define STTS751_REG_PROD_ID 0xFD
#define STTS751_REG_MAN_ID 0xFE
#define STTS751_REG_REV_ID 0xFF
#define STTS751_0_PROD_ID 0x00
#define STTS751_1_PROD_ID 0x01
#define ST_MAN_ID 0x53
/* -------------------------------------------------------------------------- */
/* --- GLOBAL VARIABLES ----------------------------------------------------- */
/* Signal handling variables */
static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
static int i2c_dev = -1;
/* -------------------------------------------------------------------------- */
/* --- SUBFUNCTIONS DECLARATION --------------------------------------------- */
static void sig_handler(int sigio);
static void usage(void);
/* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */
int main(int argc, char ** argv)
{
int i, err;
static struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
uint8_t val;
uint8_t high_byte, low_byte;
int8_t h;
float temperature;
/* Parse command line options */
while ((i = getopt(argc, argv, "hd:")) != -1) {
switch (i) {
case 'h':
usage();
return EXIT_SUCCESS;
break;
case 'd':
if (optarg != NULL) {
/* TODO */
}
break;
default:
printf("ERROR: argument parsing options, 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 );
printf( "+++ Start of I2C test program +++\n" );
/* Open I2C port expander */
err = i2c_linuxdev_open( I2C_DEVICE, I2C_PORT_STTS751, &i2c_dev );
if ( (err != 0) || (i2c_dev <= 0) )
{
printf( "ERROR: failed to open I2C device %s (err=%i)\n", I2C_DEVICE, err );
return EXIT_FAILURE;
}
/* Get temperature sensor product ID */
err = i2c_linuxdev_read( i2c_dev, I2C_PORT_STTS751, STTS751_REG_PROD_ID, &val );
if ( err != 0 )
{
printf( "ERROR: failed to read I2C device %s (err=%i)\n", I2C_DEVICE, err );
return EXIT_FAILURE;;
}
switch( val )
{
case STTS751_0_PROD_ID:
printf("INFO: Product ID: STTS751-0\n");
break;
case STTS751_1_PROD_ID:
printf("INFO: Product ID: STTS751-1\n");
break;
default:
printf("ERROR: Product ID: UNKNOWN\n");
return EXIT_FAILURE;;
}
/* Get temperature sensor Manufacturer ID */
err = i2c_linuxdev_read( i2c_dev, I2C_PORT_STTS751, STTS751_REG_MAN_ID, &val );
if ( err != 0 )
{
printf( "ERROR: failed to read I2C device %s (err=%i)\n", I2C_DEVICE, err );
return EXIT_FAILURE;;
}
if ( val != ST_MAN_ID )
{
printf( "ERROR: Manufacturer ID: UNKNOWN\n" );
return EXIT_FAILURE;;
}
else
{
printf("INFO: Manufacturer ID: 0x%02X\n", val);
}
/* Get temperature sensor revision number */
err = i2c_linuxdev_read( i2c_dev, I2C_PORT_STTS751, STTS751_REG_REV_ID, &val );
if ( err != 0 )
{
printf( "ERROR: failed to read I2C device %s (err=%i)\n", I2C_DEVICE, err );
return EXIT_FAILURE;;
}
printf("INFO: Revision number: 0x%02X\n", val);
/* Set conversion resolution to 12 bits */
err = i2c_linuxdev_write( i2c_dev, I2C_PORT_STTS751, STTS751_REG_CONF, 0x8C ); /* TODO: do not hardcode the whole byte */
if ( err != 0 )
{
printf( "ERROR: failed to write I2C device 0x%02X (err=%i)\n", I2C_PORT_STTS751, err );
return EXIT_FAILURE;
}
/* Set conversion rate to 1 / second */
err = i2c_linuxdev_write( i2c_dev, I2C_PORT_STTS751, STTS751_REG_RATE, 0x04 );
if ( err != 0 )
{
printf( "ERROR: failed to write I2C device 0x%02X (err=%i)\n", I2C_PORT_STTS751, err );
return EXIT_FAILURE;
}
while ((quit_sig != 1) && (exit_sig != 1)) {
/* Read Temperature LSB */
err = i2c_linuxdev_read( i2c_dev, I2C_PORT_STTS751, STTS751_REG_TEMP_L, &low_byte );
if ( err != 0 )
{
printf( "ERROR: failed to read I2C device 0x%02X (err=%i)\n", I2C_PORT_STTS751, err );
return EXIT_FAILURE;
}
/* Read Temperature MSB */
err = i2c_linuxdev_read( i2c_dev, I2C_PORT_STTS751, STTS751_REG_TEMP_H, &high_byte );
if ( err != 0 )
{
printf( "ERROR: failed to read I2C device 0x%02X (err=%i)\n", I2C_PORT_STTS751, err );
return EXIT_FAILURE;
}
h = (int8_t)high_byte;
temperature = ((h << 8) | low_byte) / 256.0;
printf( "Temperature: %f C (h:0x%02X l:0x%02X)\n", temperature, high_byte, low_byte );
wait_ms( 100 );
}
/* Terminate */
printf( "+++ End of I2C test program +++\n" );
err = i2c_linuxdev_close( i2c_dev );
if ( err != 0 )
{
printf( "ERROR: failed to close I2C device (err=%i)\n", err );
return EXIT_FAILURE;
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* --- SUBFUNCTIONS DEFINITION ---------------------------------------------- */
static void sig_handler(int sigio) {
if (sigio == SIGQUIT) {
quit_sig = 1;
} else if((sigio == SIGINT) || (sigio == SIGTERM)) {
exit_sig = 1;
}
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
static void usage(void) {
printf("~~~ Library version string~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf(" %s\n", lgw_version_info());
printf("~~~ Available options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf(" -h print this help\n");
printf(" -d <path> use Linux I2C device driver\n");
printf(" => default path: " I2C_DEVICE "\n");
}
/* --- EOF ------------------------------------------------------------------ */

View file

@ -0,0 +1,204 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2019 Semtech
Description:
Minimum test program for the loragw_reg module
License: Revised BSD License, see LICENSE.TXT file include in the project
*/
/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */
/* Fix an issue between POSIX and C99 */
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* getopt, access */
#include <math.h>
#include "loragw_reg.h"
#include "loragw_aux.h"
#include "loragw_hal.h"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
#define LINUXDEV_PATH_DEFAULT "/dev/spidev0.0"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
extern const struct lgw_reg_s loregs[LGW_TOTALREGS+1];
/* -------------------------------------------------------------------------- */
/* --- SUBFUNCTIONS DECLARATION --------------------------------------------- */
static void usage(void);
/* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */
int main(int argc, char ** argv)
{
int x, i;
int32_t val;
bool error_found = false;
uint8_t rand_values[LGW_TOTALREGS];
bool reg_ignored[LGW_TOTALREGS]; /* store register to be ignored */
uint8_t reg_val;
uint8_t reg_max;
/* SPI interfaces */
const char spidev_path_default[] = LINUXDEV_PATH_DEFAULT;
const char * spidev_path = spidev_path_default;
/* Parse command line options */
while ((i = getopt(argc, argv, "hd:")) != -1) {
switch (i) {
case 'h':
usage();
return EXIT_SUCCESS;
break;
case 'd':
if (optarg != NULL) {
spidev_path = optarg;
}
break;
default:
printf("ERROR: argument parsing options, use -h option for help\n");
usage();
return EXIT_FAILURE;
}
}
/* Board reset */
if (system("./reset_lgw.sh start") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
x = lgw_connect(spidev_path);
if (x != LGW_REG_SUCCESS) {
printf("ERROR: failed to connect\n");
return -1;
}
/* The following registers cannot be tested this way */
memset(reg_ignored, 0, sizeof reg_ignored);
reg_ignored[SX1302_REG_COMMON_CTRL0_CLK32_RIF_CTRL] = true; /* all test fails if we set this one to 1 */
/* Test 1: read all registers and check default value for non-read-only registers */
printf("## TEST#1: read all registers and check default value for non-read-only registers\n");
error_found = false;
for (i = 0; i < LGW_TOTALREGS; i++) {
if (loregs[i].rdon == 0) {
x = lgw_reg_r(i, &val);
if (x != LGW_REG_SUCCESS) {
printf("ERROR: failed to read register at index %d\n", i);
return -1;
}
if (val != loregs[i].dflt) {
printf("ERROR: default value for register at index %d is %d, should be %d\n", i, val, loregs[i].dflt);
error_found = true;
}
}
}
printf("------------------\n");
printf(" TEST#1 %s\n", (error_found == false) ? "PASSED" : "FAILED");
printf("------------------\n\n");
/* Test 2: read/write test on all non-read-only, non-pulse, non-w0clr, non-w1clr registers */
printf("## TEST#2: read/write test on all non-read-only, non-pulse, non-w0clr, non-w1clr registers\n");
/* Write all registers with a random value */
error_found = false;
for (i = 0; i < LGW_TOTALREGS; i++) {
if ((loregs[i].rdon == 0) && (reg_ignored[i] == false)) {
/* Peek a random value different form the default reg value */
reg_max = pow(2, loregs[i].leng) - 1;
if (loregs[i].leng == 1) {
reg_val = !loregs[i].dflt;
} else {
/* ensure random value is not the default one */
do {
if (loregs[i].sign == 1) {
reg_val = rand() % (reg_max / 2);
} else {
reg_val = rand() % reg_max;
}
} while (reg_val == loregs[i].dflt);
}
/* Write selected value */
x = lgw_reg_w(i, reg_val);
if (x != LGW_REG_SUCCESS) {
printf("ERROR: failed to read register at index %d\n", i);
return -1;
}
/* store value for later check */
rand_values[i] = reg_val;
}
}
/* Read all registers and check if we got proper random value back */
for (i = 0; i < LGW_TOTALREGS; i++) {
if ((loregs[i].rdon == 0) && (loregs[i].chck == 1) && (reg_ignored[i] == false)) {
x = lgw_reg_r(i, &val);
if (x != LGW_REG_SUCCESS) {
printf("ERROR: failed to read register at index %d\n", i);
return -1;
}
/* check value */
if (val != rand_values[i]) {
printf("ERROR: value read from register at index %d differs from the written value (w:%u r:%d)\n", i, rand_values[i], val);
error_found = true;
} else {
//printf("INFO: MATCH reg %d (%u, %u)\n", i, rand_values[i], (uint8_t)val);
}
}
}
printf("------------------\n");
printf(" TEST#2 %s\n", (error_found == false) ? "PASSED" : "FAILED");
printf("------------------\n\n");
x = lgw_disconnect();
if (x != LGW_REG_SUCCESS) {
printf("ERROR: failed to disconnect\n");
return -1;
}
/* Board reset */
if (system("./reset_lgw.sh stop") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* --- SUBFUNCTIONS DEFINITION ---------------------------------------------- */
static void usage(void) {
printf("~~~ Library version string~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf(" %s\n", lgw_version_info());
printf("~~~ Available options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf(" -h print this help\n");
printf(" -d <path> use Linux SPI device driver\n");
printf(" => default path: " LINUXDEV_PATH_DEFAULT "\n");
}
/* --- EOF ------------------------------------------------------------------ */

View file

@ -0,0 +1,208 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2019 Semtech
Description:
Minimum test program for the loragw_spi module
License: Revised BSD License, see LICENSE.TXT file include in the project
*/
/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */
/* Fix an issue between POSIX and C99 */
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h> /* sigaction */
#include <unistd.h> /* getopt, access */
#include <time.h>
#include "loragw_spi.h"
#include "loragw_aux.h"
#include "loragw_hal.h"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
#define BUFF_SIZE 1024
#define SX1302_AGC_MCU_MEM 0x0000
#define SX1302_REG_COMMON 0x5600
#define SX1302_REG_AGC_MCU 0x5780
#define LINUXDEV_PATH_DEFAULT "/dev/spidev0.0"
/* -------------------------------------------------------------------------- */
/* --- GLOBAL VARIABLES ----------------------------------------------------- */
/* Signal handling variables */
static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
/* -------------------------------------------------------------------------- */
/* --- SUBFUNCTIONS DECLARATION --------------------------------------------- */
static void sig_handler(int sigio);
static void usage(void);
/* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */
int main(int argc, char ** argv)
{
static struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
uint8_t data = 0;
uint8_t test_buff[BUFF_SIZE];
uint8_t read_buff[BUFF_SIZE];
int cycle_number = 0;
int i;
uint16_t size;
/* SPI interfaces */
const char spidev_path_default[] = LINUXDEV_PATH_DEFAULT;
const char * spidev_path = spidev_path_default;
void *spi_target = NULL;
/* Parse command line options */
while ((i = getopt(argc, argv, "hd:")) != -1) {
switch (i) {
case 'h':
usage();
return EXIT_SUCCESS;
break;
case 'd':
if (optarg != NULL) {
spidev_path = optarg;
}
break;
default:
printf("ERROR: argument parsing options, 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 );
/* Board reset */
if (system("./reset_lgw.sh start") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
printf("Beginning of test for loragw_spi.c\n");
i = lgw_spi_open(spidev_path, &spi_target);
if (i != 0) {
printf("ERROR: failed to open SPI device %s\n", spidev_path);
return -1;
}
/* normal R/W test */
/* TODO */
/* burst R/W test, small bursts << LGW_BURST_CHUNK */
/* TODO */
/* burst R/W test, large bursts >> LGW_BURST_CHUNK */
/* TODO */
lgw_spi_r(spi_target, LGW_SPI_MUX_TARGET_SX1302, SX1302_REG_COMMON + 6, &data);
printf("SX1302 version: 0x%02X\n", data);
lgw_spi_r(spi_target, LGW_SPI_MUX_TARGET_SX1302, SX1302_REG_AGC_MCU + 0, &data);
lgw_spi_w(spi_target, LGW_SPI_MUX_TARGET_SX1302, SX1302_REG_AGC_MCU + 0, 0x06); /* mcu_clear, host_prog */
srand(time(NULL));
/* databuffer R/W stress test */
while ((quit_sig != 1) && (exit_sig != 1)) {
size = rand() % BUFF_SIZE;
for (i = 0; i < size; ++i) {
test_buff[i] = rand() & 0xFF;
}
printf("Cycle %i > ", cycle_number);
lgw_spi_wb(spi_target, LGW_SPI_MUX_TARGET_SX1302, SX1302_AGC_MCU_MEM, test_buff, size);
lgw_spi_rb(spi_target, LGW_SPI_MUX_TARGET_SX1302, SX1302_AGC_MCU_MEM, read_buff, size);
for (i=0; ((i<size) && (test_buff[i] == read_buff[i])); ++i);
if (i != size) {
printf("error during the buffer comparison\n");
printf("Written values:\n");
for (i=0; i<size; ++i) {
printf(" %02X ", test_buff[i]);
if (i%16 == 15) printf("\n");
}
printf("\n");
printf("Read values:\n");
for (i=0; i<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", size);
++cycle_number;
}
}
lgw_spi_close(spi_target);
printf("End of test for loragw_spi.c\n");
/* Board reset */
if (system("./reset_lgw.sh stop") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* --- SUBFUNCTIONS DEFINITION ---------------------------------------------- */
static void sig_handler(int sigio) {
if (sigio == SIGQUIT) {
quit_sig = 1;
} else if((sigio == SIGINT) || (sigio == SIGTERM)) {
exit_sig = 1;
}
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
static void usage(void) {
printf("~~~ Library version string~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf(" %s\n", lgw_version_info());
printf("~~~ Available options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf(" -h print this help\n");
printf(" -d <path> use Linux SPI device driver\n");
printf(" => default path: " LINUXDEV_PATH_DEFAULT "\n");
}
/* --- EOF ------------------------------------------------------------------ */

View file

@ -0,0 +1,216 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2019 Semtech
Description:
Minimum test program for the sx1250 module
License: Revised BSD License, see LICENSE.TXT file include in the project
*/
/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */
/* Fix an issue between POSIX and C99 */
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h> /* sigaction */
#include <unistd.h> /* getopt, access */
#include "loragw_spi.h"
#include "loragw_aux.h"
#include "loragw_reg.h"
#include "loragw_hal.h"
#include "loragw_sx1250.h"
#include "loragw_sx1302.h"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
#define BUFF_SIZE 16
#define LINUXDEV_PATH_DEFAULT "/dev/spidev0.0"
/* -------------------------------------------------------------------------- */
/* --- GLOBAL VARIABLES ----------------------------------------------------- */
/* Signal handling variables */
static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
/* -------------------------------------------------------------------------- */
/* --- SUBFUNCTIONS DECLARATION --------------------------------------------- */
static void sig_handler(int sigio);
static void usage(void);
/* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */
int main(int argc, char ** argv)
{
static struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
uint8_t test_buff[BUFF_SIZE];
uint8_t read_buff[BUFF_SIZE];
uint32_t test_val, read_val;
int cycle_number = 0;
int i, x;
/* SPI interfaces */
const char spidev_path_default[] = LINUXDEV_PATH_DEFAULT;
const char * spidev_path = spidev_path_default;
/* Parse command line options */
while ((i = getopt(argc, argv, "hd:")) != -1) {
switch (i) {
case 'h':
usage();
return EXIT_SUCCESS;
break;
case 'd':
if (optarg != NULL) {
spidev_path = optarg;
}
break;
default:
printf("ERROR: argument parsing options, 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 );
/* Board reset */
if (system("./reset_lgw.sh start") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
x = lgw_connect(spidev_path);
if (x != LGW_REG_SUCCESS) {
printf("ERROR: Failed to connect to the concentrator using SPI %s\n", spidev_path);
return EXIT_FAILURE;
}
/* Reset radios */
for (i = 0; i < LGW_RF_CHAIN_NB; i++) {
sx1302_radio_reset(i, LGW_RADIO_TYPE_SX1250);
sx1302_radio_set_mode(i, LGW_RADIO_TYPE_SX1250);
}
/* Select the radio which provides the clock to the sx1302 */
sx1302_radio_clock_select(0);
/* Ensure we can control the radio */
lgw_reg_w(SX1302_REG_COMMON_CTRL0_HOST_RADIO_CTRL, 0x01);
/* Ensure PA/LNA are disabled */
lgw_reg_w(SX1302_REG_AGC_MCU_CTRL_FORCE_HOST_FE_CTRL, 1);
lgw_reg_w(SX1302_REG_AGC_MCU_RF_EN_A_PA_EN, 0);
lgw_reg_w(SX1302_REG_AGC_MCU_RF_EN_A_LNA_EN, 0);
/* Set Radio in Standby mode */
test_buff[0] = (uint8_t)STDBY_XOSC;
sx1250_write_command(0, SET_STANDBY, test_buff, 1);
sx1250_write_command(1, SET_STANDBY, test_buff, 1);
wait_ms(10);
test_buff[0] = 0x00;
sx1250_read_command(0, GET_STATUS, test_buff, 1);
printf("Radio0: get_status: 0x%02X\n", test_buff[0]);
sx1250_read_command(1, GET_STATUS, test_buff, 1);
printf("Radio1: get_status: 0x%02X\n", test_buff[0]);
/* databuffer R/W stress test */
while ((quit_sig != 1) && (exit_sig != 1)) {
test_buff[0] = rand() & 0x7F;
test_buff[1] = rand() & 0xFF;
test_buff[2] = rand() & 0xFF;
test_buff[3] = rand() & 0xFF;
test_val = (test_buff[0] << 24) | (test_buff[1] << 16) | (test_buff[2] << 8) | (test_buff[3] << 0);
sx1250_write_command(0, SET_RF_FREQUENCY, test_buff, 4);
read_buff[0] = 0x08;
read_buff[1] = 0x8B;
read_buff[2] = 0x00;
read_buff[3] = 0x00;
read_buff[4] = 0x00;
read_buff[5] = 0x00;
read_buff[6] = 0x00;
sx1250_read_command(0, READ_REGISTER, read_buff, 7);
read_val = (read_buff[3] << 24) | (read_buff[4] << 16) | (read_buff[5] << 8) | (read_buff[6] << 0);
printf("Cycle %i > ", cycle_number);
if (read_val != test_val) {
printf("error during the buffer comparison\n");
printf("Written value: %08X\n", test_val);
printf("Read value: %08X\n", read_val);
return EXIT_FAILURE;
} else {
printf("did a %i-byte R/W on a register with no error\n", 4);
++cycle_number;
}
}
lgw_disconnect();
printf("End of test for loragw_spi_sx1250.c\n");
/* Board reset */
if (system("./reset_lgw.sh stop") != 0) {
printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
exit(EXIT_FAILURE);
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* --- SUBFUNCTIONS DEFINITION ---------------------------------------------- */
static void sig_handler(int sigio) {
if (sigio == SIGQUIT) {
quit_sig = 1;
} else if((sigio == SIGINT) || (sigio == SIGTERM)) {
exit_sig = 1;
}
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
static void usage(void) {
printf("~~~ Library version string~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf(" %s\n", lgw_version_info());
printf("~~~ Available options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf(" -h print this help\n");
printf(" -d <path> use Linux SPI device driver\n");
printf(" => default path: " LINUXDEV_PATH_DEFAULT "\n");
}
/* --- EOF ------------------------------------------------------------------ */