sx1302_hal/libloragw/tst/test_loragw_com.c

427 lines
13 KiB
C
Raw Normal View History

v2.0.0 > #### New features * Added support for USB interface between the HOST and the concentrator, for sx1250 based concentrator only. * Added support for Listen-Before-Talk for AS923 region, using the additional sx1261 radio from the Semtech Corecell reference design v3. * Added support for Spectral Scan with additional sx1261 radio from the Semtech Corecell reference design v3. * Added support for SX1303 chip, for further Fine Timestamping support. * Merged the master-fdd-cn490 branch to bring support for CN490 Full-Duplex reference design. It is an integration of the releases v1.1.0, v1.1.1, v1.1.2 described below. > #### Changes * HAL: Reworked the complete communication layer. A new loragw_com module has been introduced to handle switching from a USB or a SPI communication interface, aligned function prototypes for sx125x, sx1250 and sx1261 radios. For USB, a mode has been added to group SPI write commands request to the STM32 MCU, in order to optimize latency during time critical configuration phases. * HAL: Added preliminary support for Fine Timestamping for TDOA localization. * HAL: Updated AGC firmware to v6: add configurable delay for PA to start, add Listen-Before-Talk support. * HAL: Added new API function lgw_demod_setconf() to set global demodulator settings. * HAL: Added new API functions for Spectral Scan. * Packet Forwarder: The type of interface is configurable in the global_conf.json file: com_type can be "USB" or "SPI". * Packet Forwarder: Changed the parameters to configure fine timestamping in the global_conf.json. * Packet Forwarder: Added sections to configure the spectral scan and Listen-Before-Talk features. * Packet Forwarder: Added a new thread for background spectral scan example, to show how to use the spectral scan API provided by the HAL, without interfering with the main tasks of the gateway (aka Receive uplinks and transmit downlinks). * Packet Forwarder: Added "nhdr" field parsing from "txpk" JSON downlink request in order to be able to send beacon request from Network Server. * Packet Forwarder: Added chan_multiSF_All in global_conf.json to choose which spreading factors to enable for multi-sf demodulators. * Packet Forwarder: Updated PROTOCOL.md to v1.6. * Tools: added util_spectral_scan, a standalone spectral scanner utility. > #### Notes * This release has been validated on the Semtech Corecell reference design v3 with USB interface. v1.1.2 > Integrated in ***v2.0.0*** from ***master-fdd-cn490*** branch. * packet forwarder: updated global_conf.json.sx1255.CN490.full-duplex with RSSI temperature compensation coefficients, and updated RSSI offset for radio 1. v1.1.1 > Integrated in ***v2.0.0*** from ***master-fdd-cn490*** branch. * HAL: Updated SX1302 LNA/PA LUT configuration for Full Duplex CN490 reference design. * test_loragw_hal_rx/tx: added --fdd option to enable Full Duplex * packet forwarder: updated global_conf.json.sx1255.CN490.full-duplex for CN490 reference design. v1.1.0 > Integrated in ***v2.0.0*** from ***master-fdd-cn490*** branch. * HAL: Added support for CN490 full duplex reference design.
2020-12-09 09:21:09 +01:00
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2019 Semtech
Description:
Minimum test program for the loragw_com 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 <errno.h>
#include "loragw_com.h"
#include "loragw_aux.h"
#include "loragw_hal.h"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
#define RAND_RANGE(min, max) (rand() % (max + 1 - min) + min)
/* -------------------------------------------------------------------------- */
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
#define BUFF_SIZE_SPI 1024
#define BUFF_SIZE_USB 4096
#define SX1302_AGC_MCU_MEM 0x0000
#define SX1302_REG_COMMON 0x5600
#define SX1302_REG_AGC_MCU 0x5780
#define COM_TYPE_DEFAULT LGW_COM_SPI
#define COM_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 */
/* Buffers */
static uint8_t * test_buff = NULL;
static uint8_t * read_buff = NULL;
/* -------------------------------------------------------------------------- */
/* --- SUBFUNCTIONS DECLARATION --------------------------------------------- */
static void sig_handler(int sigio);
static void usage(void);
static void exit_failure(void);
/* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */
int main(int argc, char ** argv)
{
static struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
uint16_t max_buff_size;
uint8_t data = 0;
int cycle_number = 0;
int i, x;
uint16_t size;
/* COM interfaces */
const char com_path_default[] = COM_PATH_DEFAULT;
const char * com_path = com_path_default;
lgw_com_type_t com_type = COM_TYPE_DEFAULT;
/* Parse command line options */
while ((i = getopt(argc, argv, "hd:u")) != -1) {
switch (i) {
case 'h':
usage();
return EXIT_SUCCESS;
break;
case 'd':
if (optarg != NULL) {
com_path = optarg;
}
break;
case 'u':
com_type = LGW_COM_USB;
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 (com_type == LGW_COM_SPI) {
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_com.c\n");
x = lgw_com_open(com_type, com_path);
if (x != 0) {
printf("ERROR: failed to open COM device %s\n", com_path);
exit(EXIT_FAILURE);
}
/* 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 */
x = lgw_com_r(LGW_SPI_MUX_TARGET_SX1302, SX1302_REG_COMMON + 6, &data);
if (x != 0) {
printf("ERROR (%d): failed to read register\n", __LINE__);
exit_failure();
}
printf("SX1302 version: 0x%02X\n", data);
x = lgw_com_r(LGW_SPI_MUX_TARGET_SX1302, SX1302_REG_AGC_MCU + 0, &data);
if (x != 0) {
printf("ERROR (%d): failed to read register\n", __LINE__);
exit_failure();
}
x = lgw_com_w(LGW_SPI_MUX_TARGET_SX1302, SX1302_REG_AGC_MCU + 0, 0x06); /* mcu_clear, host_prog */
if (x != 0) {
printf("ERROR (%d): failed to write register\n", __LINE__);
exit_failure();
}
srand(time(NULL));
/* Allocate buffers according to com type capabilities */
max_buff_size = (com_type == LGW_COM_SPI) ? BUFF_SIZE_SPI : BUFF_SIZE_USB;
test_buff = (uint8_t*)malloc(max_buff_size * sizeof(uint8_t));
if (test_buff == NULL) {
printf("ERROR: failed to allocate memory for test_buff - %s\n", strerror(errno));
exit_failure();
}
read_buff = (uint8_t*)malloc(max_buff_size * sizeof(uint8_t));
if (read_buff == NULL) {
printf("ERROR: failed to allocate memory for read_buff - %s\n", strerror(errno));
exit_failure();
}
/* databuffer R/W stress test */
while ((quit_sig != 1) && (exit_sig != 1)) {
/*************************************************
*
* WRITE BURST TEST
*
* ***********************************************/
size = rand() % max_buff_size;
for (i = 0; i < size; ++i) {
test_buff[i] = rand() & 0xFF;
}
printf("Cycle %i> ", cycle_number);
/* Write burst with random data */
x = lgw_com_wb(LGW_SPI_MUX_TARGET_SX1302, SX1302_AGC_MCU_MEM, test_buff, size);
if (x != 0) {
printf("ERROR (%d): failed to write burst\n", __LINE__);
exit_failure();
}
/* Read back */
x = lgw_com_rb(LGW_SPI_MUX_TARGET_SX1302, SX1302_AGC_MCU_MEM, read_buff, size);
if (x != 0) {
printf("ERROR (%d): failed to read burst\n", __LINE__);
exit_failure();
}
/* Compare read / write buffers */
for (i=0; ((i<size) && (test_buff[i] == read_buff[i])); ++i);
if (i != size) {
printf("error during the buffer comparison\n");
/* Print what has been written */
printf("Written values:\n");
for (i=0; i<size; ++i) {
printf(" %02X ", test_buff[i]);
if (i%16 == 15) printf("\n");
}
printf("\n");
/* Print what has been read back */
printf("Read values:\n");
for (i=0; i<size; ++i) {
printf(" %02X ", read_buff[i]);
if (i%16 == 15) printf("\n");
}
printf("\n");
/* exit */
exit_failure();
} else {
printf("did a %i-byte R/W on a data buffer with no error\n", size);
++cycle_number;
}
/*************************************************
*
* WRITE SINGLE BYTE TEST
*
* ***********************************************/
/* Single byte r/w test */
printf("Cycle %i> ", cycle_number);
test_buff[0] = rand() & 0xFF;
/* Write single byte */
x = lgw_com_w(LGW_SPI_MUX_TARGET_SX1302, SX1302_AGC_MCU_MEM, test_buff[0]);
if (x != 0) {
printf("ERROR (%d): failed to write burst\n", __LINE__);
exit_failure();
}
/* Read back */
x = lgw_com_r(LGW_SPI_MUX_TARGET_SX1302, SX1302_AGC_MCU_MEM, &read_buff[0]);
if (x != 0) {
printf("ERROR (%d): failed to read burst\n", __LINE__);
exit_failure();
}
/* Compare read / write bytes */
if (test_buff[0] != read_buff[0]) {
printf("error during the byte comparison\n");
/* Print what has been written */
printf("Written value: %02X\n", test_buff[0]);
/* Print what has been read back */
printf("Read values: %02X\n", read_buff[0]);
/* exit */
exit_failure();
} else {
printf("did a 1-byte R/W on a data buffer with no error\n");
++cycle_number;
}
/*************************************************
*
* WRITE WITH BULK (USB only mode)
*
* ***********************************************/
x = lgw_com_set_write_mode(LGW_COM_WRITE_MODE_BULK);
if (x != 0) {
printf("ERROR (%d): failed to set bulk write mode\n", __LINE__);
exit_failure();
}
uint16_t num_req = RAND_RANGE(1, 254); /* keep one req for remaining bytes */
size = RAND_RANGE(num_req, max_buff_size / 2); /* TODO: test proper limit */
for (i = 0; i < size; i++) {
test_buff[i] = rand() & 0xFF;
}
uint16_t size_per_req = size / num_req;
uint16_t size_remaining = size - (num_req * size_per_req);
printf("Cycle %i> ", cycle_number);
uint16_t size_written = 0;
for (i = 0; i < num_req; i++) {
x = lgw_com_wb(LGW_SPI_MUX_TARGET_SX1302, SX1302_AGC_MCU_MEM + size_written, test_buff + size_written, size_per_req);
if (x != 0) {
printf("ERROR (%d): failed to write burst\n", __LINE__);
exit_failure();
}
size_written += (size_per_req);
}
if (size_remaining > 0) {
x = lgw_com_wb(LGW_SPI_MUX_TARGET_SX1302, SX1302_AGC_MCU_MEM + size_written, test_buff + size_written, size_remaining);
if (x != 0) {
printf("ERROR (%d): failed to write burst\n", __LINE__);
exit_failure();
}
}
/* Send data to MCU (UBS mode only) */
x = lgw_com_flush();
if (x != 0) {
printf("ERROR (%d): failed to flush write\n", __LINE__);
exit_failure();
}
/* Read back */
x = lgw_com_rb(LGW_SPI_MUX_TARGET_SX1302, SX1302_AGC_MCU_MEM, read_buff, size);
if (x != 0) {
printf("ERROR (%d): failed to read burst\n", __LINE__);
exit_failure();
}
/* Compare read / write buffers */
for (i=0; ((i<size) && (test_buff[i] == read_buff[i])); ++i);
if (i != size) {
printf("error during the buffer comparison\n");
/* Print what has been written */
printf("Written values:\n");
for (i=0; i<size; ++i) {
printf(" %02X ", test_buff[i]);
if (i%16 == 15) printf("\n");
}
printf("\n");
/* Print what has been read back */
printf("Read values:\n");
for (i=0; i<size; ++i) {
printf(" %02X ", read_buff[i]);
if (i%16 == 15) printf("\n");
}
printf("\n");
/* exit */
exit_failure();
} else {
printf("did a %i-byte bulk R/W on a data buffer with no error\n", size);
++cycle_number;
}
}
lgw_com_close();
printf("End of test for loragw_com.c\n");
/* deallocate buffers */
if (test_buff != NULL) {
free(test_buff);
test_buff = NULL;
}
if (read_buff != NULL) {
free(read_buff);
read_buff = NULL;
}
if (com_type == LGW_COM_SPI) {
/* 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 exit_failure(void) {
lgw_com_close();
printf("End of test for loragw_com.c\n");
/* deallocate buffers */
if (test_buff != NULL) {
free(test_buff);
test_buff = NULL;
}
if (read_buff != NULL) {
free(read_buff);
read_buff = NULL;
}
exit(EXIT_FAILURE);
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
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(" -u set COM type as USB (default is SPI)\n");
printf(" -d <path> COM path to be used to connect the concentrator\n");
printf(" => default path (SPI): " COM_PATH_DEFAULT "\n");
}
/* --- EOF ------------------------------------------------------------------ */