> #### 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.
This commit is contained in:
Michael Coracin 2020-12-09 09:21:09 +01:00
commit 2c14708bdb
107 changed files with 13516 additions and 3249 deletions

View file

@ -0,0 +1,83 @@
### get external defined data
include ../target.cfg
### User defined build options
ARCH ?=
CROSS_COMPILE ?=
BUILD_MODE := release
OBJDIR = obj
### ----- AVOID MODIFICATIONS BELLOW ------ AVOID MODIFICATIONS BELLOW ----- ###
ifeq '$(BUILD_MODE)' 'alpha'
$(warning /\/\/\/ Building in 'alpha' mode \/\/\/\)
WARN_CFLAGS :=
OPT_CFLAGS := -O0
DEBUG_CFLAGS := -g
LDFLAGS :=
else ifeq '$(BUILD_MODE)' 'debug'
$(warning /\/\/\/ Building in 'debug' mode \/\/\/\)
WARN_CFLAGS := -Wall -Wextra
OPT_CFLAGS := -O2
DEBUG_CFLAGS := -g
LDFLAGS :=
else ifeq '$(BUILD_MODE)' 'release'
$(warning /\/\/\/ Building in 'release' mode \/\/\/\)
WARN_CFLAGS := -Wall -Wextra
OPT_CFLAGS := -O2 -ffunction-sections -fdata-sections
DEBUG_CFLAGS :=
LDFLAGS := -Wl,--gc-sections
else
$(error BUILD_MODE must be set to either 'alpha', 'debug' or 'release')
endif
### Application-specific variables
APP_NAME := spectral_scan
APP_LIBS := -lloragw -lm -ltinymt32 -lrt
### Environment constants
LIB_PATH := ../libloragw
### Expand build options
CFLAGS := -std=c99 $(WARN_CFLAGS) $(OPT_CFLAGS) $(DEBUG_CFLAGS)
CC := $(CROSS_COMPILE)gcc
AR := $(CROSS_COMPILE)ar
### General build targets
all: $(APP_NAME)
clean:
rm -f obj/*.o
rm -f $(APP_NAME)
install:
ifneq ($(strip $(TARGET_IP)),)
ifneq ($(strip $(TARGET_DIR)),)
ifneq ($(strip $(TARGET_USR)),)
@echo "---- Copying spectral_scan files to $(TARGET_IP):$(TARGET_DIR)"
@ssh $(TARGET_USR)@$(TARGET_IP) "mkdir -p $(TARGET_DIR)"
@scp spectral_scan $(TARGET_USR)@$(TARGET_IP):$(TARGET_DIR)
else
@echo "ERROR: TARGET_USR is not configured in target.cfg"
endif
else
@echo "ERROR: TARGET_DIR is not configured in target.cfg"
endif
else
@echo "ERROR: TARGET_IP is not configured in target.cfg"
endif
$(OBJDIR):
mkdir -p $(OBJDIR)
### Compile main program
$(OBJDIR)/$(APP_NAME).o: src/$(APP_NAME).c | $(OBJDIR)
$(CC) -c $< -o $@ $(CFLAGS) -Iinc -I../libloragw/inc
### Link everything together
$(APP_NAME): $(OBJDIR)/$(APP_NAME).o $(LIB_PATH)/libloragw.a
$(CC) -L$(LIB_PATH) -L../libtools $^ -o $@ $(LDFLAGS) $(APP_LIBS)
### EOF

View file

@ -0,0 +1,64 @@
#!/usr/bin/python
# -*- encoding: utf-8 -*-
# ______ _
# / _____) _ | |
# ( (____ _____ ____ _| |_ _____ ____| |__
# \____ \| ___ | (_ _) ___ |/ ___) _ \
# _____) ) ____| | | || |_| ____( (___| | | |
# (______/|_____)_|_|_| \__)_____)\____)_| |_|
# (C)2020 Semtech
#
# Description:
# Spectral Scan CSV result file plot - v0.3.0
#
# License: Revised BSD License, see LICENSE.TXT file include in the project
#Library importation
import pylab as pl
import numpy as np
import csv
import sys
#Read argument
if len(sys.argv) >= 2:
filename = sys.argv[1]
else:
print ("Usage: %s <filename>" %sys.argv[0])
sys.exit()
#Initiate array
rssi = []
freq = []
#Process .csv file
with open(filename, 'r') as csvfile:
reader = csv.reader(csvfile, delimiter=',', quotechar='|')
for row in reader:
f=int(row[0])//1000 #frequency
freq.append(f)
rssi_line=[]
rssi_val=[]
for k in range(1,(len(row)-1)//2):
rssi_line.append(int(row[k*2]))
rssi_val.append(int(row[k*2-1]))
rssi.append(rssi_line)
#Set x to frequency axis and y to signal level axis
A = np.array(rssi).T
A = np.flip(A,0)
rssi_val =np.flip(rssi_val,0)
#Find max value to scale heatmap then plot.
maxx = max(max(rssi))
print(maxx, A)
h=pl.imshow(A , cmap='afmhot', vmin=0, vmax=maxx, aspect='auto', origin='lower', interpolation='nearest')
pl.xticks(range(0,len(freq),10),freq[::10])
pl.yticks(range(0,len(rssi[1]),2),rssi_val[0::2])
pl.show()

View file

@ -0,0 +1,85 @@
______ _
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2020 Semtech
Spectral Scan Utility
=====================
## 1. Introduction
This software allows to scan the spectral band using the additional sx1261 radio
of the Semtech Corecell reference design.
It computes a RSSI histogram on several frequencies, that will help to detect
occupied bands and get interferer profiles.
It logs the histogram in a .csv file.
## 2. Command line options
### 2.1. General options ###
`-h`
will display a short help and version informations.
### 2.2. SPI options ###
`-d spidev_path`
specifies the spi_dev path to be used to acces the sx1261 radio.
### 2.3. USB options ###
`-u -d tty_path`
specifies the tty path to be used to acces the MCU which will redirect commands
to the sx1261 radio.
## 3. Usage
This utility is autonomous and will perform a full initialization of the
concentrator. So it cannot be run in parallel of the packet forwarder.
It will scan channels as specified on the command line, the first channel being
the given frequency (-f argument) and the other channels (number given with -n
argument) shifted by 200kHz from the previous one.
It then generates a CSV file with the RSSI histogram for each channel.
## 4. Plotting the results
In order to have a visual representation of the spectral scan results, a python
script is provided here. rssi_histogram.csv is the file generated by the
spectral_scan utility.
```bash
python3 plot_rssi_histogram.py rssi_histogram.csv
```
The python script uses `pylab` and `numpy` packages, so both have to be installed
prior to using the `plot_rssi_histogram.py` script.
## 5. Legal notice
The information presented in this project documentation does not form part of
any quotation or contract, is believed to be accurate and reliable and may be
changed without notice. No liability will be accepted by the publisher for any
consequence of its use. Publication thereof does not convey nor imply any
license under patent or other industrial or intellectual property rights.
Semtech assumes no responsibility or liability whatsoever for any failure or
unexpected operation resulting from misuse, neglect improper installation,
repair or improper handling or unusual physical or electrical stress
including, but not limited to, exposure to parameters beyond the specified
maximum ratings or operation outside the specified range.
SEMTECH PRODUCTS ARE NOT DESIGNED, INTENDED, AUTHORIZED OR WARRANTED TO BE
SUITABLE FOR USE IN LIFE-SUPPORT APPLICATIONS, DEVICES OR SYSTEMS OR OTHER
CRITICAL APPLICATIONS. INCLUSION OF SEMTECH PRODUCTS IN SUCH APPLICATIONS IS
UNDERSTOOD TO BE UNDERTAKEN SOLELY AT THE CUSTOMER'S OWN RISK. Should a
customer purchase or use Semtech products for any such unauthorized
application, the customer shall indemnify and hold Semtech and its officers,
employees, subsidiaries, affiliates, and distributors harmless against all
claims, costs damages and attorney fees which could arise.
*EOF*

View file

@ -0,0 +1,367 @@
/*
______ _
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2020 Semtech
Description:
Spectral Scan Utility
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 <inttypes.h> /* PRIx64, PRIu64... */
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <signal.h> /* sigaction */
#include <getopt.h> /* getopt_long */
#include "loragw_hal.h"
#include "loragw_aux.h"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
#define COM_TYPE_DEFAULT LGW_COM_SPI
#define COM_PATH_DEFAULT "/dev/spidev0.0"
#define SX1261_PATH_DEFAULT "/dev/spidev0.1"
#define DEFAULT_CLK_SRC 0
#define DEFAULT_RADIO_TYPE LGW_RADIO_TYPE_SX1250
#define DEFAULT_FREQ_HZ 863100000U
#define DEFAULT_NB_CHAN 35
#define DEFAULT_NB_SCAN 2000
#define DEFAULT_RSSI_OFFSET -11 /* RSSI offset of SX1261 */
#define DEFAULT_LOG_NAME "rssi_histogram"
/* -------------------------------------------------------------------------- */
/* --- PRIVATE VARIABLES ---------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* --- 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(" -u Set COM type as USB (default is SPI)\n");
printf(" -d [path] Path to the main COM interface\n");
printf(" => default path: " COM_PATH_DEFAULT "\n");
printf(" -D [path] Path to the SX1261 SPI interface (not used for USB)\n");
printf(" => default path: " SX1261_PATH_DEFAULT "\n");
printf(" -f <float> Scan start frequency, in MHz\n");
printf(" -n <uint> Number of channels to scan\n");
printf(" -s <uint> Number of scan points per frequency step [1..65535]\n");
printf(" -o <int> RSSI Offset of the sx1261 path, in dB [-127..128]\n");
printf(" -l <char> Log file name\n");
}
/* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */
int main(int argc, char **argv)
{
int i, j, x;
unsigned int arg_u;
double arg_d = 0.0;
int arg_i;
char arg_s[64];
struct lgw_conf_board_s boardconf;
struct lgw_conf_rxrf_s rfconf;
struct lgw_conf_sx1261_s sx1261conf;
/* COM interface */
const char com_path_default[] = COM_PATH_DEFAULT;
const char * com_path = com_path_default;
lgw_com_type_t com_type = COM_TYPE_DEFAULT;
const char sx1261_path_default[] = SX1261_PATH_DEFAULT;
const char * sx1261_path = sx1261_path_default;
/* Spectral Scan */
uint32_t freq_hz = DEFAULT_FREQ_HZ;
uint8_t nb_channels = DEFAULT_NB_CHAN;
uint16_t nb_scan = DEFAULT_NB_SCAN;
int8_t rssi_offset = DEFAULT_RSSI_OFFSET;
int16_t levels[LGW_SPECTRAL_SCAN_RESULT_SIZE];
uint16_t results[LGW_SPECTRAL_SCAN_RESULT_SIZE];
char log_file_name[64] = DEFAULT_LOG_NAME;
FILE * log_file = NULL;
struct timeval tm_start;
lgw_spectral_scan_status_t status;
/* 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, "hud:f:n:o:s:l:D:", long_options, &option_index)) != -1) {
switch (i) {
case 'h':
usage();
return -1;
break;
case 'u':
com_type = LGW_COM_USB;
break;
case 'd':
com_path = optarg;
break;
case 'D':
sx1261_path = optarg;
break;
case 'f': /* <float> Scan start 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 {
freq_hz = (uint32_t)((arg_d*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
}
break;
case 'n': /* <uint> Number of channels to scan */
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 {
if (arg_u > 255) {
printf("ERROR: Number of channels must be < 255\n");
return EXIT_FAILURE;
}
nb_channels = (uint8_t)arg_u;
}
break;
case 's':
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 {
if (arg_u > 65535) {
printf("ERROR: Number of scan must be < 65535\n");
return EXIT_FAILURE;
}
nb_scan = (uint16_t)arg_u;
}
break;
case 'o': /* <uint> SX1261 RSSI offset in dB */
i = sscanf(optarg, "%d", &arg_i);
if (i != 1) {
printf("ERROR: argument parsing of -o argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
if (arg_i < -127 || arg_i > 128) {
printf("ERROR: SX1261 RSSI value out of range\n");
return EXIT_FAILURE;
}
rssi_offset = (int8_t)arg_i;
}
break;
case 'l': /* -l <char> Log file name */
j = sscanf(optarg, "%63s", arg_s);
if (j != 1) {
printf("ERROR: argument parsing of -l argument. Use -h to print help\n");
return EXIT_FAILURE;
} else {
sprintf(log_file_name, "%s", arg_s);
}
break;
default:
printf("ERROR: argument parsing\n");
usage();
return -1;
}
}
printf("==\n");
printf("== Spectral Scan: freq_hz=%uHz, nb_channels=%u, nb_scan=%u, rssi_offset=%ddB\n", freq_hz, nb_channels, nb_scan, rssi_offset);
printf("==\n");
if (com_type == LGW_COM_SPI) {
/* 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 = DEFAULT_CLK_SRC;
boardconf.full_duplex = false;
boardconf.com_type = com_type;
strncpy(boardconf.com_path, com_path, sizeof boardconf.com_path);
boardconf.com_path[sizeof boardconf.com_path - 1] = '\0'; /* ensure string termination */
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;
rfconf.freq_hz = 867500000; /* dummy */
rfconf.type = DEFAULT_RADIO_TYPE;
rfconf.tx_enable = false;
rfconf.single_input_mode = 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 = 868500000; /* dummy */
rfconf.type = DEFAULT_RADIO_TYPE;
rfconf.tx_enable = false;
rfconf.single_input_mode = false;
if (lgw_rxrf_setconf(1, &rfconf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure rxrf 1\n");
return EXIT_FAILURE;
}
/* Configure the sx1261 for spectral scan */
memset(&sx1261conf, 0, sizeof sx1261conf);
sx1261conf.enable = true;
strncpy(sx1261conf.spi_path, sx1261_path, sizeof sx1261conf.spi_path);
sx1261conf.spi_path[sizeof sx1261conf.spi_path - 1] = '\0'; /* ensure string termination */
sx1261conf.rssi_offset = rssi_offset;
sx1261conf.lbt_conf.enable = false;
if (lgw_sx1261_setconf(&sx1261conf) != LGW_HAL_SUCCESS) {
printf("ERROR: failed to configure sx1261\n");
return EXIT_FAILURE;
}
/* Start the gateway, initialize sx1261 radio for scanning */
x = lgw_start();
if (x != 0) {
printf("ERROR: failed to start the gateway\n");
return EXIT_FAILURE;
}
/* create log file */
strcat(log_file_name,".csv");
log_file = fopen(log_file_name, "w");
if (log_file == NULL) {
printf("ERROR: impossible to create log file %s\n", log_file_name);
return EXIT_FAILURE;
}
/* Launch Spectral Scan on each channels */
for (j = 0; j < nb_channels; j++) {
x = lgw_spectral_scan_start(freq_hz, 2000);
if (x != 0) {
printf("ERROR: spectral scan start failed\n");
continue;
}
/* Wait for scan to be completed */
timeout_start(&tm_start);
do {
/* handle timeout */
if (timeout_check(tm_start, 2000) != 0) {
printf("ERROR: %s: TIMEOUT on Spectral Scan\n", __FUNCTION__);
continue;
}
/* get spectral scan status */
status = LGW_SPECTRAL_SCAN_STATUS_UNKNOWN;
x = lgw_spectral_scan_get_status(&status);
if (x != 0) {
printf("ERROR: spectral scan status failed\n");
break;
}
wait_ms(10);
} while (status != LGW_SPECTRAL_SCAN_STATUS_COMPLETED && status != LGW_SPECTRAL_SCAN_STATUS_ABORTED);
if (status == LGW_SPECTRAL_SCAN_STATUS_COMPLETED) {
memset(levels, 0, sizeof levels);
memset(results, 0, sizeof results);
x = lgw_spectral_scan_get_results(levels, results);
if (x != 0) {
printf("ERROR: spectral scan get results failed\n");
continue;
}
/* log results */
fprintf(log_file, "%u", freq_hz);
for (i = 0; i < LGW_SPECTRAL_SCAN_RESULT_SIZE; i++) {
fprintf(log_file, ",%d,%u", levels[i], results[i]);
}
fprintf(log_file, "\n");
/* print results */
printf("%u: ", freq_hz);
for (i = 0; i < LGW_SPECTRAL_SCAN_RESULT_SIZE; i++) {
printf("%u ", results[i]);
}
printf("\n");
/* Next frequency to scan */
freq_hz += 200000; /* 200kHz channels */
} else if (status == LGW_SPECTRAL_SCAN_STATUS_ABORTED) {
printf("INFO: spectral scan has been aborted\n");
} else {
printf("ERROR: spectral scan status us unexpected 0x%02X\n", status);
}
}
/* close log file */
fclose(log_file);
/* Stop the gateway */
x = lgw_stop();
if (x != 0) {
printf("ERROR: failed to stop the gateway\n");
return EXIT_FAILURE;
}
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;
}
/* --- EOF ------------------------------------------------------------------ */