├── .gitignore ├── LICENSE ├── Makefile ├── VERSION ├── fpga ├── SX1301_FPGA_125K_NOTCH_LBT_bitmap_v27.bin ├── SX1301_FPGA_125K_NOTCH_SPECTRAL_SCAN_bitmap_v27.bin └── readme.md ├── libloragw ├── 99-libftdi.rules ├── Makefile ├── inc │ ├── imst_rpi.h │ ├── kerlink.h │ ├── linklabs_blowfish_rpi.h │ ├── loragw_aux.h │ ├── loragw_fpga.h │ ├── loragw_gps.h │ ├── loragw_hal.h │ ├── loragw_lbt.h │ ├── loragw_radio.h │ ├── loragw_reg.h │ ├── loragw_spi.h │ ├── loragw_sx125x.h │ ├── loragw_sx1272_fsk.h │ ├── loragw_sx1272_lora.h │ ├── loragw_sx1276_fsk.h │ ├── loragw_sx1276_lora.h │ ├── lorank.h │ └── multitech.h ├── install_ftdi.txt ├── library.cfg ├── readme.md ├── src │ ├── agc_fw.var │ ├── arb_fw.var │ ├── cal_fw.var │ ├── loragw_aux.c │ ├── loragw_fpga.c │ ├── loragw_gps.c │ ├── loragw_hal.c │ ├── loragw_lbt.c │ ├── loragw_radio.c │ ├── loragw_reg.c │ ├── loragw_spi.ftdi.c │ └── loragw_spi.native.c └── tst │ ├── test_loragw_cal.c │ ├── test_loragw_gps.c │ ├── test_loragw_hal.c │ ├── test_loragw_reg.c │ └── test_loragw_spi.c ├── mac-howto ├── readme.md ├── reset_lgw.sh ├── util_lbt_test ├── Makefile ├── readme.md └── src │ └── util_lbt_test.c ├── util_pkt_logger ├── Makefile ├── global_conf.json ├── inc │ └── parson.h ├── local_conf.json ├── readme.md └── src │ ├── parson.c │ └── util_pkt_logger.c ├── util_spectral_scan ├── Makefile ├── readme.md └── src │ └── util_spectral_scan.c ├── util_spi_stress ├── Makefile ├── readme.md └── src │ └── util_spi_stress.c ├── util_tx_continuous ├── Makefile ├── readme.md └── src │ └── util_tx_continuous.c └── util_tx_test ├── Makefile ├── readme.md └── src └── util_tx_test.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.o 3 | *.swp 4 | *.bak 5 | 6 | .cproject 7 | .project 8 | .settings/ 9 | 10 | libloragw/inc/config.h 11 | 12 | libloragw/test_* 13 | 14 | util_lbt_test/util_lbt_test 15 | util_pkt_logger/util_pkt_logger 16 | util_spectral_scan/util_spectral_scan 17 | util_spi_stress/util_spi_stress 18 | util_tx_continuous/util_tx_continuous 19 | util_tx_test/util_tx_test 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, SEMTECH S.A. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the Semtech corporation nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | 27 | --- For the parson library used by the packet logger --- 28 | 29 | Parson ( http://kgabis.github.com/parson/ ) 30 | Copyright (c) 2012 Krzysztof Gabis 31 | 32 | Permission is hereby granted, free of charge, to any person obtaining a copy 33 | of this software and associated documentation files (the "Software"), to deal 34 | in the Software without restriction, including without limitation the rights 35 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 36 | copies of the Software, and to permit persons to whom the Software is 37 | furnished to do so, subject to the following conditions: 38 | 39 | The above copyright notice and this permission notice shall be included in 40 | all copies or substantial portions of the Software. 41 | 42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 43 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 44 | ITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 45 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 46 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 47 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 48 | THE SOFTWARE. 49 | 50 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ### Environment constants 2 | 3 | ARCH ?= 4 | CROSS_COMPILE ?= 5 | export 6 | 7 | ### general build targets 8 | 9 | all: 10 | $(MAKE) all -e -C libloragw 11 | $(MAKE) all -e -C util_pkt_logger 12 | $(MAKE) all -e -C util_spi_stress 13 | $(MAKE) all -e -C util_lbt_test 14 | $(MAKE) all -e -C util_tx_test 15 | $(MAKE) all -e -C util_tx_continuous 16 | $(MAKE) all -e -C util_spectral_scan 17 | 18 | clean: 19 | $(MAKE) clean -e -C libloragw 20 | $(MAKE) clean -e -C util_pkt_logger 21 | $(MAKE) clean -e -C util_spi_stress 22 | $(MAKE) clean -e -C util_lbt_test 23 | $(MAKE) clean -e -C util_tx_test 24 | $(MAKE) clean -e -C util_tx_continuous 25 | $(MAKE) clean -e -C util_spectral_scan 26 | 27 | ### EOF 28 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 4.0.0 2 | -------------------------------------------------------------------------------- /fpga/SX1301_FPGA_125K_NOTCH_LBT_bitmap_v27.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheThingsArchive/lora_gateway/4e2d95646e3a34224b460e69b6b417796b83b4ce/fpga/SX1301_FPGA_125K_NOTCH_LBT_bitmap_v27.bin -------------------------------------------------------------------------------- /fpga/SX1301_FPGA_125K_NOTCH_SPECTRAL_SCAN_bitmap_v27.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheThingsArchive/lora_gateway/4e2d95646e3a34224b460e69b6b417796b83b4ce/fpga/SX1301_FPGA_125K_NOTCH_SPECTRAL_SCAN_bitmap_v27.bin -------------------------------------------------------------------------------- /fpga/readme.md: -------------------------------------------------------------------------------- 1 | / _____) _ | | 2 | ( (____ _____ ____ _| |_ _____ ____| |__ 3 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 4 | _____) ) ____| | | || |_| ____( (___| | | | 5 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 6 | (C)2013 Semtech-Cycleo 7 | 8 | FPGA images for LoRa Gateway SX1301AP2-PCB_E336 9 | =============================================== 10 | 11 | 1. Content 12 | ---------- 13 | 14 | This directory contains the FPGA images to be programmed in the Semtech's 15 | Reference Design board (SX1301AP2-PCB_E336) flash memory. 16 | 17 | The different images contain the following features: 18 | 19 | * SX1301_FPGA_125K_NOTCH_LBT_bitmap_v27.bin: 20 | - 125K Notch filter for TX 21 | - Listen-Before-Talk 22 | 23 | * SX1301_FPGA_125K_NOTCH_SPECTRAL_SCAN_bitmap_v27.bin: 24 | - 125K Notch filter for TX 25 | - Background Spectral Scan 26 | 27 | 2. Usage 28 | -------- 29 | 30 | The following parameters have to be set when using the Lattice Diamond 31 | Programmer software: 32 | 33 | Device Family -> iCE40 34 | Device -> iCE40LP1K 35 | Operation -> SPI Flash Programming 36 | -> Programming file: select one of the provided bin image 37 | -> SPI Vendor: Micron 38 | -> SPI Device: SPI-M25P10-A 39 | 40 | 3. Legal notice 41 | ---------------- 42 | 43 | The information presented in this project documentation does not form part of 44 | any quotation or contract, is believed to be accurate and reliable and may be 45 | changed without notice. No liability will be accepted by the publisher for any 46 | consequence of its use. Publication thereof does not convey nor imply any 47 | license under patent or other industrial or intellectual property rights. 48 | Semtech assumes no responsibility or liability whatsoever for any failure or 49 | unexpected operation resulting from misuse, neglect improper installation, 50 | repair or improper handling or unusual physical or electrical stress 51 | including, but not limited to, exposure to parameters beyond the specified 52 | maximum ratings or operation outside the specified range. 53 | 54 | SEMTECH PRODUCTS ARE NOT DESIGNED, INTENDED, AUTHORIZED OR WARRANTED TO BE 55 | SUITABLE FOR USE IN LIFE-SUPPORT APPLICATIONS, DEVICES OR SYSTEMS OR OTHER 56 | CRITICAL APPLICATIONS. INCLUSION OF SEMTECH PRODUCTS IN SUCH APPLICATIONS IS 57 | UNDERSTOOD TO BE UNDERTAKEN SOLELY AT THE CUSTOMER'S OWN RISK. Should a 58 | customer purchase or use Semtech products for any such unauthorized 59 | application, the customer shall indemnify and hold Semtech and its officers, 60 | employees, subsidiaries, affiliates, and distributors harmless against all 61 | claims, costs damages and attorney fees which could arise. 62 | 63 | *EOF* 64 | -------------------------------------------------------------------------------- /libloragw/99-libftdi.rules: -------------------------------------------------------------------------------- 1 | # FTDI Devices: FT232BM/L/Q, FT245BM/L/Q, FT232RL/Q, FT245RL/Q, VNC1L with VDPS Firmware 2 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0664", GROUP="plugdev" 3 | 4 | # FTDI Devices: FT2232C/D/L, FT2232HL/Q 5 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="0664", GROUP="plugdev" 6 | 7 | # FTDI Devices: FT4232HL/Q 8 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="0664", GROUP="plugdev" 9 | -------------------------------------------------------------------------------- /libloragw/Makefile: -------------------------------------------------------------------------------- 1 | ### get external defined data 2 | 3 | LIBLORAGW_VERSION := `cat ../VERSION` 4 | include library.cfg 5 | 6 | ### constant symbols 7 | 8 | ARCH ?= 9 | CROSS_COMPILE ?= 10 | CC := $(CROSS_COMPILE)gcc 11 | AR := $(CROSS_COMPILE)ar 12 | 13 | 14 | ### Test if the file has been configured, do not accept the default 15 | 16 | ifeq ($(CFG_SPI),???) 17 | $(error Please specify CFG_SPI in lora_gateway/libloragw/library.cfg first!) 18 | endif 19 | 20 | ifeq ($(PLATFORM),???) 21 | $(error Please specify PLATFORM in lora_gateway/libloragw/library.cfg first!) 22 | endif 23 | 24 | 25 | ### library.cfg configuration file processing 26 | 27 | ifeq ($(CFG_SPI),native) 28 | CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I. -fPIC 29 | CFG_SPI_MSG := Linux native SPI driver 30 | CFG_SPI_OPT := CFG_SPI_NATIVE 31 | else ifeq ($(CFG_SPI),ftdi) 32 | ifeq ($(PLATFORM),multitech) 33 | ifeq ($(SDKTARGETSYSROOT),) 34 | CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I. -I/opt/mlinux/3.2.0/sysroots/arm926ejste-mlinux-linux-gnueabi/usr/include/libftdi1 35 | else 36 | CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I. -I$(SDKTARGETSYSROOT)/usr/include/libftdi1 37 | endif 38 | else 39 | CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I. -fPIC 40 | endif 41 | CFG_SPI_MSG := FTDI SPI-over-USB bridge using libmpsse/libftdi/libusb 42 | CFG_SPI_OPT := CFG_SPI_FTDI 43 | else ifeq ($(CFG_SPI),mac) 44 | CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I. -I/opt/local/include -I/usr/local/include -I/opt/local/include/libftdi1 45 | CFG_SPI_MSG := FTDI SPI-over-USB bridge on the MAC using libmpsse/libftdi/libusb 46 | CFG_SPI_OPT := CFG_SPI_FTDI 47 | else 48 | $(error No SPI physical layer selected, check ../target.cfg file.) 49 | endif 50 | 51 | OBJDIR = obj 52 | INCLUDES = $(wildcard inc/*.h) 53 | 54 | ### linking options 55 | 56 | ifeq ($(CFG_SPI),native) 57 | LIBS := -lloragw -lrt -lm 58 | else ifeq ($(CFG_SPI),ftdi) 59 | LIBS := -lloragw -lrt -lmpsse -lm 60 | else ifeq ($(CFG_SPI),mac) 61 | LIBS := -lloragw -lmpsse -lm 62 | endif 63 | 64 | ### general build targets 65 | 66 | all: libloragw.a test_loragw_spi test_loragw_reg test_loragw_hal test_loragw_gps test_loragw_cal 67 | 68 | clean: 69 | rm -f libloragw.a 70 | rm -f test_loragw_* 71 | rm -f $(OBJDIR)/*.o 72 | rm -f inc/config.h 73 | 74 | ### transpose library.cfg into a C header file : config.h 75 | 76 | inc/config.h: ../VERSION library.cfg 77 | @echo "*** Checking libloragw library configuration ***" 78 | @rm -f $@ 79 | #File initialization 80 | @echo "#ifndef _LORAGW_CONFIGURATION_H" >> $@ 81 | @echo "#define _LORAGW_CONFIGURATION_H" >> $@ 82 | # Release version 83 | @echo "Release version : $(LIBLORAGW_VERSION)" 84 | @echo " #define LIBLORAGW_VERSION "\"$(LIBLORAGW_VERSION)\""" >> $@ 85 | # SPI interface 86 | @echo "SPI interface : $(CFG_SPI_MSG)" 87 | @echo " #define $(CFG_SPI_OPT) 1" >> $@ 88 | # Debug options 89 | @echo " #define DEBUG_AUX $(DEBUG_AUX)" >> $@ 90 | @echo " #define DEBUG_SPI $(DEBUG_SPI)" >> $@ 91 | @echo " #define DEBUG_REG $(DEBUG_REG)" >> $@ 92 | @echo " #define DEBUG_HAL $(DEBUG_HAL)" >> $@ 93 | @echo " #define DEBUG_GPS $(DEBUG_GPS)" >> $@ 94 | @echo " #define DEBUG_GPIO $(DEBUG_GPIO)" >> $@ 95 | @echo " #define DEBUG_LBT $(DEBUG_LBT)" >> $@ 96 | # Platform selection 97 | @echo " #include \"$(PLATFORM).h\"" >> $@ 98 | # end of file 99 | @echo "#endif" >> $@ 100 | @echo "*** Configuration seems ok ***" 101 | 102 | ### library module target 103 | 104 | $(OBJDIR): 105 | mkdir -p $(OBJDIR) 106 | 107 | $(OBJDIR)/%.o: src/%.c $(INCLUDES) inc/config.h | $(OBJDIR) 108 | $(CC) -c $(CFLAGS) $< -o $@ 109 | 110 | ifeq ($(CFG_SPI),native) 111 | $(OBJDIR)/loragw_spi.o: src/loragw_spi.native.c inc/loragw_spi.h inc/config.h | $(OBJDIR) 112 | $(CC) -c $(CFLAGS) $< -o $@ 113 | else ifeq ($(CFG_SPI),ftdi) 114 | $(OBJDIR)/loragw_spi.o: src/loragw_spi.ftdi.c inc/loragw_spi.h inc/config.h | $(OBJDIR) 115 | $(CC) -c $(CFLAGS) $< -o $@ 116 | else ifeq ($(CFG_SPI),mac) 117 | $(OBJDIR)/loragw_spi.o: src/loragw_spi.ftdi.c inc/loragw_spi.h inc/config.h | $(OBJDIR) 118 | $(CC) -c $(CFLAGS) $< -o $@ 119 | endif 120 | 121 | $(OBJDIR)/loragw_hal.o: src/loragw_hal.c $(INCLUDES) src/arb_fw.var src/agc_fw.var src/cal_fw.var inc/config.h | $(OBJDIR) 122 | $(CC) -c $(CFLAGS) $< -o $@ 123 | 124 | ### static library 125 | 126 | libloragw.a: $(OBJDIR)/loragw_hal.o $(OBJDIR)/loragw_gps.o $(OBJDIR)/loragw_reg.o $(OBJDIR)/loragw_spi.o $(OBJDIR)/loragw_aux.o $(OBJDIR)/loragw_radio.o $(OBJDIR)/loragw_fpga.o $(OBJDIR)/loragw_lbt.o 127 | $(AR) rcs $@ $^ 128 | 129 | ### test programs 130 | 131 | test_loragw_spi: tst/test_loragw_spi.c libloragw.a 132 | $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS) 133 | 134 | test_loragw_reg: tst/test_loragw_reg.c libloragw.a 135 | $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS) 136 | 137 | test_loragw_hal: tst/test_loragw_hal.c libloragw.a 138 | $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS) 139 | 140 | test_loragw_gps: tst/test_loragw_gps.c libloragw.a 141 | $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS) 142 | 143 | test_loragw_cal: tst/test_loragw_cal.c libloragw.a src/cal_fw.var 144 | $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS) 145 | 146 | ### EOF 147 | -------------------------------------------------------------------------------- /libloragw/inc/imst_rpi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * imst_rpi.h 3 | * 4 | * Created on: Dec 30, 2015 5 | * Author: gonzalocasas 6 | */ 7 | 8 | #ifndef _IMST_RPI_H_ 9 | #define _IMST_RPI_H_ 10 | 11 | /* Human readable platform definition */ 12 | #define DISPLAY_PLATFORM "IMST + Rpi" 13 | 14 | /* parameters for native spi */ 15 | #define SPI_SPEED 8000000 16 | #define SPI_DEV_PATH "/dev/spidev0.0" 17 | #define SPI_CS_CHANGE 0 18 | 19 | /* parameters for a FT2232H */ 20 | #define VID 0x0403 21 | #define PID 0x6014 22 | 23 | #endif /* _IMST_RPI_H_ */ 24 | -------------------------------------------------------------------------------- /libloragw/inc/kerlink.h: -------------------------------------------------------------------------------- 1 | /* 2 | * kerlink.h 3 | * 4 | * Created on: Sep 21, 2015 5 | * Author: ruud 6 | */ 7 | 8 | #ifndef _KERLINK_H_ 9 | #define _KERLINK_H_ 10 | 11 | /* Human readable platform definition */ 12 | #define DISPLAY_PLATFORM "Kerlink" 13 | 14 | /* parameters for native spi */ 15 | #define SPI_SPEED 8000000 16 | #define SPI_DEV_PATH "/dev/spidev32766.0" 17 | #define SPI_CS_CHANGE 1 18 | 19 | /* parameters for a FT2232H */ 20 | #define VID 0x0403 21 | #define PID 0x6010 22 | 23 | 24 | #endif /* _KERLINK_H_ */ 25 | -------------------------------------------------------------------------------- /libloragw/inc/linklabs_blowfish_rpi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * linklabs_blowfish_rpi.h 3 | * 4 | * Created on: Feb 23, 2016 5 | * Author: ticapix 6 | */ 7 | 8 | #ifndef _LINKLABS_BLOWFISH_H_ 9 | #define _LINKLABS_BLOWFISH_H_ 10 | 11 | /* Human readable platform definition */ 12 | #define DISPLAY_PLATFORM "LinkLabs Blowfish + Rpi" 13 | 14 | /* parameters for native spi */ 15 | #define SPI_SPEED 8000000 16 | #define SPI_DEV_PATH "/dev/spidev0.0" 17 | #define SPI_CS_CHANGE 0 18 | 19 | /* parameters for a FT2232H */ 20 | #define VID 0x0403 21 | #define PID 0x6014 22 | 23 | #endif /* _LINKLABS_BLOWFISH_H_ */ 24 | -------------------------------------------------------------------------------- /libloragw/inc/loragw_aux.h: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | LoRa concentrator HAL common auxiliary functions 11 | 12 | License: Revised BSD License, see LICENSE.TXT file include in the project 13 | Maintainer: Sylvain Miermont 14 | */ 15 | 16 | 17 | #ifndef _LORAGW_AUX_H 18 | #define _LORAGW_AUX_H 19 | 20 | /* -------------------------------------------------------------------------- */ 21 | /* --- DEPENDANCIES --------------------------------------------------------- */ 22 | 23 | #include "config.h" /* library configuration options (dynamically generated) */ 24 | 25 | /* -------------------------------------------------------------------------- */ 26 | /* --- PUBLIC MACROS -------------------------------------------------------- */ 27 | 28 | /** 29 | @brief Get a particular bit value from a byte 30 | @param b [in] Any byte from which we want a bit value 31 | @param p [in] Position of the bit in the byte [0..7] 32 | @param n [in] Number of bits we want to get 33 | @return The value corresponding the requested bits 34 | */ 35 | #define TAKE_N_BITS_FROM(b, p, n) (((b) >> (p)) & ((1 << (n)) - 1)) 36 | 37 | /* -------------------------------------------------------------------------- */ 38 | /* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */ 39 | 40 | /** 41 | @brief Wait for a certain time (millisecond accuracy) 42 | @param t number of milliseconds to wait. 43 | */ 44 | void wait_ms(unsigned long t); 45 | 46 | #endif 47 | 48 | /* --- EOF ------------------------------------------------------------------ */ 49 | -------------------------------------------------------------------------------- /libloragw/inc/loragw_fpga.h: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Functions used to handle FPGA register access for LoRa concentrator. 11 | Registers are addressed by name. 12 | Multi-bytes registers are handled automatically. 13 | Read-modify-write is handled automatically. 14 | 15 | License: Revised BSD License, see LICENSE.TXT file include in the project 16 | Maintainer: Michael Coracin 17 | */ 18 | 19 | #ifndef _LORAGW_FPGA_REG_H 20 | #define _LORAGW_FPGA_REG_H 21 | 22 | /* -------------------------------------------------------------------------- */ 23 | /* --- DEPENDANCIES --------------------------------------------------------- */ 24 | 25 | #include /* C99 types */ 26 | #include /* bool type */ 27 | 28 | /* -------------------------------------------------------------------------- */ 29 | /* --- PUBLIC CONSTANTS ----------------------------------------------------- */ 30 | 31 | #define LGW_REG_SUCCESS 0 32 | #define LGW_REG_ERROR -1 33 | 34 | /* 35 | auto generated register mapping for C code 36 | this file contains autogenerated C struct used to access the FPGA registers 37 | this file is autogenerated from registers description 38 | */ 39 | #define LGW_FPGA_SOFT_RESET 0 40 | #define LGW_FPGA_FPGA_FEATURE 1 41 | #define LGW_FPGA_VERSION 2 42 | #define LGW_FPGA_FPGA_STATUS 3 43 | #define LGW_FPGA_CTRL_FEATURE_START 4 44 | #define LGW_FPGA_CTRL_RADIO_RESET 5 45 | #define LGW_FPGA_CTRL_INPUT_SYNC_I 6 46 | #define LGW_FPGA_CTRL_INPUT_SYNC_Q 7 47 | #define LGW_FPGA_CTRL_OUTPUT_SYNC 8 48 | #define LGW_FPGA_CTRL_INVERT_IQ 9 49 | #define LGW_FPGA_HISTO_RAM_ADDR 10 50 | #define LGW_FPGA_HISTO_RAM_DATA 11 51 | #define LGW_FPGA_HISTO_TEMPO 12 52 | #define LGW_FPGA_HISTO_NB_READ 13 53 | #define LGW_FPGA_TIMESTAMP 14 54 | #define LGW_FPGA_LBT_TIMESTAMP_CH 15 55 | #define LGW_FPGA_LBT_TIMESTAMP_SELECT_CH 16 56 | #define LGW_FPGA_LBT_TIMESTAMP_NB_CH 17 57 | #define LGW_FPGA_SPI_MASTER_SPEED_DIVIDER 18 58 | #define LGW_FPGA_NB_READ_RSSI 19 59 | #define LGW_FPGA_PLL_LOCK_TIME 20 60 | #define LGW_FPGA_RSSI_TARGET 21 61 | #define LGW_FPGA_LSB_START_FREQ 22 62 | #define LGW_FPGA_SPI_MUX_CTRL 23 63 | #define LGW_FPGA_TOTALREGS 24 64 | 65 | /* -------------------------------------------------------------------------- */ 66 | /* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */ 67 | 68 | int lgw_fpga_configure(void); 69 | 70 | /** 71 | @brief LoRa concentrator FPGA register write 72 | @param register_id register number in the data structure describing registers 73 | @param reg_value signed value to write to the register (for u32, use cast) 74 | @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) 75 | */ 76 | int lgw_fpga_reg_w(uint16_t register_id, int32_t reg_value); 77 | 78 | /** 79 | @brief LoRa concentrator FPGA register read 80 | @param register_id register number in the data structure describing registers 81 | @param reg_value pointer to a variable where to write register read value 82 | @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) 83 | */ 84 | int lgw_fpga_reg_r(uint16_t register_id, int32_t *reg_value); 85 | 86 | /** 87 | @brief LoRa concentrator FPGA register burst write 88 | @param register_id register number in the data structure describing registers 89 | @param data pointer to byte array that will be sent to the LoRa concentrator 90 | @param size size of the transfer, in byte(s) 91 | @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) 92 | */ 93 | int lgw_fpga_reg_wb(uint16_t register_id, uint8_t *data, uint16_t size); 94 | 95 | /** 96 | @brief LoRa concentrator FPGA register burst read 97 | @param register_id register number in the data structure describing registers 98 | @param data pointer to byte array that will be written from the LoRa concentrator 99 | @param size size of the transfer, in byte(s) 100 | @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) 101 | */ 102 | int lgw_fpga_reg_rb(uint16_t register_id, uint8_t *data, uint16_t size); 103 | 104 | #endif 105 | /* --- EOF ------------------------------------------------------------------ */ 106 | -------------------------------------------------------------------------------- /libloragw/inc/loragw_gps.h: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Library of functions to manage a GNSS module (typically GPS) for accurate 11 | timestamping of packets and synchronisation of gateways. 12 | A limited set of module brands/models are supported. 13 | 14 | License: Revised BSD License, see LICENSE.TXT file include in the project 15 | Maintainer: Sylvain Miermont 16 | */ 17 | 18 | 19 | #ifndef _LORAGW_GPS_H 20 | #define _LORAGW_GPS_H 21 | 22 | /* -------------------------------------------------------------------------- */ 23 | /* --- DEPENDANCIES --------------------------------------------------------- */ 24 | 25 | /* fix an issue between POSIX and C99 */ 26 | #define _GNU_SOURCE 27 | #include /* C99 types */ 28 | #include /* time library */ 29 | #include /* speed_t */ 30 | 31 | #include "config.h" /* library configuration options (dynamically generated) */ 32 | 33 | /* -------------------------------------------------------------------------- */ 34 | /* --- PUBLIC TYPES --------------------------------------------------------- */ 35 | 36 | /** 37 | @struct coord_s 38 | @brief Time solution required for timestamp to absolute time conversion 39 | */ 40 | struct tref { 41 | time_t systime; /*!> system time when solution was calculated */ 42 | uint32_t count_us; /*!> reference concentrator internal timestamp */ 43 | struct timespec utc; /*!> reference UTC time (from GPS) */ 44 | double xtal_err; /*!> raw clock error (eg. <1 'slow' XTAL) */ 45 | }; 46 | 47 | /** 48 | @struct coord_s 49 | @brief Geodesic coordinates 50 | */ 51 | struct coord_s { 52 | double lat; /*!> latitude [-90,90] (North +, South -) */ 53 | double lon; /*!> longitude [-180,180] (East +, West -)*/ 54 | short alt; /*!> altitude in meters (WGS 84 geoid ref.) */ 55 | }; 56 | 57 | /** 58 | @enum gps_msg 59 | @brief Type of GPS (and other GNSS) sentences 60 | */ 61 | enum gps_msg { 62 | UNKNOWN, /*!> neutral value */ 63 | IGNORED, /*!> frame was not parsed by the system */ 64 | INVALID, /*!> system try to parse frame but failed */ 65 | /* NMEA messages of interest */ 66 | NMEA_RMC, /*!> Recommended Minimum data (time + date) */ 67 | NMEA_GGA, /*!> Global positioning system fix data (pos + alt) */ 68 | NMEA_GNS, /*!> GNSS fix data (pos + alt, sat number) */ 69 | NMEA_ZDA, /*!> Time and Date */ 70 | /* NMEA message useful for time reference quality assessment */ 71 | NMEA_GBS, /*!> GNSS Satellite Fault Detection */ 72 | NMEA_GST, /*!> GNSS Pseudo Range Error Statistics */ 73 | NMEA_GSA, /*!> GNSS DOP and Active Satellites (sat number) */ 74 | NMEA_GSV, /*!> GNSS Satellites in View (sat SNR) */ 75 | /* Misc. NMEA messages */ 76 | NMEA_GLL, /*!> Latitude and longitude, with time fix and status */ 77 | NMEA_TXT, /*!> Text Transmission */ 78 | NMEA_VTG, /*!> Course over ground and Ground speed */ 79 | /* uBlox proprietary NMEA messages of interest */ 80 | UBX_POSITION, /*!> */ 81 | UBX_TIME /*!> */ 82 | }; 83 | 84 | /* -------------------------------------------------------------------------- */ 85 | /* --- PUBLIC CONSTANTS ----------------------------------------------------- */ 86 | 87 | #define LGW_GPS_SUCCESS 0 88 | #define LGW_GPS_ERROR -1 89 | 90 | /* -------------------------------------------------------------------------- */ 91 | /* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */ 92 | 93 | /** 94 | @brief Configure a GPS module 95 | 96 | @param tty_path path to the TTY connected to the GPS 97 | @param gps_familly parameter (eg. ubx6 for uBlox gen.6) 98 | @param target_brate target baudrate for communication (0 keeps default target baudrate) 99 | @param fd_ptr pointer to a variable to receive file descriptor on GPS tty 100 | @return success if the function was able to connect and configure a GPS module 101 | */ 102 | int lgw_gps_enable(char* tty_path, char* gps_familly, speed_t target_brate, int* fd_ptr); 103 | 104 | /** 105 | @brief Parse messages coming from the GPS system (or other GNSS) 106 | 107 | @param serial_buff pointer to the string to be parsed 108 | @param buff_size maximum string lengths for NMEA parsing (incl. null char) 109 | @return type of frame parsed 110 | 111 | The RAW NMEA sentences are parsed to a global set of variables shared with the 112 | lgw_gps_get function. 113 | If the lgw_parse_nmea and lgw_gps_get are used in different threads, a mutex 114 | lock must be acquired before calling either function. 115 | */ 116 | enum gps_msg lgw_parse_nmea(char* serial_buff, int buff_size); 117 | 118 | /** 119 | @brief Get the GPS solution (space & time) for the concentrator 120 | 121 | @param utc pointer to store UTC time, with ns precision (NULL to ignore) 122 | @param loc pointer to store coordinates (NULL to ignore) 123 | @param err pointer to store coordinates standard deviation (NULL to ignore) 124 | @return success if the chosen elements could be returned 125 | 126 | This function read the global variables generated by the NMEA parsing function 127 | lgw_parse_nmea. It returns time and location data in a format that is 128 | exploitable by other functions in that library sub-module. 129 | If the lgw_parse_nmea and lgw_gps_get are used in different threads, a mutex 130 | lock must be acquired before calling either function. 131 | */ 132 | int lgw_gps_get(struct timespec* utc, struct coord_s* loc, struct coord_s* err); 133 | 134 | /** 135 | @brief Take a timestamp and UTC time and refresh reference for time conversion 136 | 137 | @param ref pointer to time reference structure 138 | @param old_ref previous time reference (NULL for initial fix) 139 | @param utc UTC time, with ns precision (leap seconds are ignored) 140 | @return success if timestamp was read and time reference could be refreshed 141 | 142 | Set systime to 0 in ref to trigger initial synchronization. 143 | */ 144 | int lgw_gps_sync(struct tref* ref, uint32_t count_us, struct timespec utc); 145 | 146 | /** 147 | @brief Convert concentrator timestamp counter value to UTC time 148 | 149 | @param ref time reference structure required for time conversion 150 | @param count_us internal timestamp counter of the LoRa concentrator 151 | @param utc pointer to store UTC time, with ns precision (leap seconds ignored) 152 | @return success if the function was able to convert timestamp to UTC 153 | 154 | This function is typically used when a packet is received to transform the 155 | internal counter-based timestamp in an absolute timestamp with an accuracy in 156 | the order of a couple microseconds (ns resolution). 157 | */ 158 | int lgw_cnt2utc(struct tref ref, uint32_t count_us, struct timespec* utc); 159 | 160 | /** 161 | @brief Convert UTC time to concentrator timestamp counter value 162 | 163 | @param ref time reference structure required for time conversion 164 | @param utc UTC time, with ns precision (leap seconds are ignored) 165 | @param count_us pointer to store internal timestamp counter of LoRa concentrator 166 | @return success if the function was able to convert UTC to timestamp 167 | 168 | This function is typically used when a packet must be sent at an accurate time 169 | (eg. to send a piggy-back response after receiving a packet from a node) to 170 | transform an absolute UTC time into a matching internal concentrator timestamp. 171 | */ 172 | int lgw_utc2cnt(struct tref ref,struct timespec utc, uint32_t* count_us); 173 | 174 | #endif 175 | 176 | /* --- EOF ------------------------------------------------------------------ */ 177 | -------------------------------------------------------------------------------- /libloragw/inc/loragw_lbt.h: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Functions used to handle the Listen Before Talk feature 11 | 12 | License: Revised BSD License, see LICENSE.TXT file include in the project 13 | Maintainer: Michael Coracin 14 | */ 15 | 16 | #ifndef _LORAGW_LBT_H 17 | #define _LORAGW_LBT_H 18 | 19 | /* -------------------------------------------------------------------------- */ 20 | /* --- DEPENDANCIES --------------------------------------------------------- */ 21 | 22 | #include /* C99 types */ 23 | #include /* bool type */ 24 | 25 | #include "loragw_hal.h" 26 | 27 | /* -------------------------------------------------------------------------- */ 28 | /* --- PUBLIC CONSTANTS ----------------------------------------------------- */ 29 | 30 | #define LGW_LBT_SUCCESS 0 31 | #define LGW_LBT_ERROR -1 32 | 33 | /* -------------------------------------------------------------------------- */ 34 | /* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */ 35 | 36 | /** 37 | @brief Set the configuration parameters for LBT feature 38 | @param conf structure containing the configuration parameters 39 | @return LGW_LBT_ERROR id the operation failed, LGW_LBT_SUCCESS else 40 | */ 41 | int lbt_setconf(struct lgw_conf_lbt_s * conf); 42 | 43 | /** 44 | @brief Configure the concentrator for LBT feature 45 | @param rf_freq frequency in Hz of the first LBT channel 46 | @param rssi_target RSSI threshold used to determine if LBT channel is busy or not 47 | @param scan_time_us duration of channel activity scanning, in microseconds 48 | @param nb_channel number of LBT channels 49 | @return LGW_LBT_ERROR id the operation failed, LGW_LBT_SUCCESS else 50 | */ 51 | int lbt_setup(uint32_t rf_freq, uint8_t rssi_target, uint16_t scan_time_us, uint8_t nb_channel); 52 | 53 | /** 54 | @brief Start the LBT FSM 55 | @return LGW_LBT_ERROR id the operation failed, LGW_LBT_SUCCESS else 56 | */ 57 | int lbt_start(void); 58 | 59 | /** 60 | @brief Configure the concentrator for LBT feature 61 | @param pkt_data pointer to downlink packet to be trabsmitted 62 | @param tx_allowed pointer to receive permission for transmission 63 | @return LGW_LBT_ERROR id the operation failed, LGW_LBT_SUCCESS else 64 | */ 65 | int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, bool * tx_allowed); 66 | 67 | #endif 68 | /* --- EOF ------------------------------------------------------------------ */ 69 | -------------------------------------------------------------------------------- /libloragw/inc/loragw_radio.h: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Functions used to handle LoRa concentrator radios. 11 | 12 | License: Revised BSD License, see LICENSE.TXT file include in the project 13 | Maintainer: Michael Coracin 14 | */ 15 | 16 | #ifndef _LORAGW_RADIO_H 17 | #define _LORAGW_RADIO_H 18 | 19 | /* -------------------------------------------------------------------------- */ 20 | /* --- DEPENDANCIES --------------------------------------------------------- */ 21 | 22 | #include /* C99 types */ 23 | #include /* bool type */ 24 | 25 | /* -------------------------------------------------------------------------- */ 26 | /* --- PUBLIC CONSTANTS ----------------------------------------------------- */ 27 | 28 | #define LGW_REG_SUCCESS 0 29 | #define LGW_REG_ERROR -1 30 | 31 | #define SX125x_32MHz_FRAC 15625 /* irreductible fraction for PLL register caculation */ 32 | 33 | /* -------------------------------------------------------------------------- */ 34 | /* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */ 35 | 36 | int setup_sx125x(uint8_t rf_chain, uint8_t rf_clkout, bool rf_enable, uint8_t rf_radio_type, uint32_t freq_hz); 37 | 38 | int lgw_sx127x_reg_w(uint8_t address, uint8_t reg_value); 39 | 40 | int lgw_sx127x_reg_r(uint8_t address, uint8_t *reg_value); 41 | 42 | int lgw_setup_sx127x(uint32_t frequency, uint8_t modulation); 43 | 44 | #endif 45 | /* --- EOF ------------------------------------------------------------------ */ 46 | -------------------------------------------------------------------------------- /libloragw/inc/loragw_spi.h: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Host specific functions to address the LoRa concentrator registers through a 11 | SPI interface. 12 | Single-byte read/write and burst read/write. 13 | Does not handle pagination. 14 | Could be used with multiple SPI ports in parallel (explicit file descriptor) 15 | 16 | License: Revised BSD License, see LICENSE.TXT file include in the project 17 | Maintainer: Sylvain Miermont 18 | */ 19 | 20 | 21 | #ifndef _LORAGW_SPI_H 22 | #define _LORAGW_SPI_H 23 | 24 | /* -------------------------------------------------------------------------- */ 25 | /* --- DEPENDANCIES --------------------------------------------------------- */ 26 | 27 | #include /* C99 types*/ 28 | 29 | #include "config.h" /* library configuration options (dynamically generated) */ 30 | 31 | /* -------------------------------------------------------------------------- */ 32 | /* --- PUBLIC CONSTANTS ----------------------------------------------------- */ 33 | 34 | #define LGW_SPI_SUCCESS 0 35 | #define LGW_SPI_ERROR -1 36 | #define LGW_BURST_CHUNK 1024 37 | 38 | #define LGW_SPI_MUX_MODE0 0x0 /* No FPGA */ 39 | #define LGW_SPI_MUX_MODE1 0x1 /* FPGA, with spi mux header */ 40 | 41 | #define LGW_SPI_MUX_TARGET_SX1301 0x0 42 | #define LGW_SPI_MUX_TARGET_FPGA 0x1 43 | #define LGW_SPI_MUX_TARGET_EEPROM 0x2 44 | #define LGW_SPI_MUX_TARGET_SX127X 0x3 45 | 46 | /* -------------------------------------------------------------------------- */ 47 | /* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */ 48 | 49 | /** 50 | @brief LoRa concentrator SPI setup (configure I/O and peripherals) 51 | @param spi_target_ptr pointer on a generic pointer to SPI target (implementation dependant) 52 | @return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR) 53 | */ 54 | 55 | int lgw_spi_open(void **spi_target_ptr); 56 | 57 | /** 58 | @brief LoRa concentrator SPI close 59 | @param spi_target generic pointer to SPI target (implementation dependant) 60 | @return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR) 61 | */ 62 | 63 | int lgw_spi_close(void *spi_target); 64 | 65 | /** 66 | @brief LoRa concentrator SPI single-byte write 67 | @param spi_target generic pointer to SPI target (implementation dependant) 68 | @param address 7-bit register address 69 | @param data data byte to write 70 | @return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR) 71 | */ 72 | int lgw_spi_w(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t data); 73 | 74 | /** 75 | @brief LoRa concentrator SPI single-byte read 76 | @param spi_target generic pointer to SPI target (implementation dependant) 77 | @param address 7-bit register address 78 | @param data data byte to write 79 | @return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR) 80 | */ 81 | int lgw_spi_r(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data); 82 | 83 | /** 84 | @brief LoRa concentrator SPI burst (multiple-byte) write 85 | @param spi_target generic pointer to SPI target (implementation dependant) 86 | @param address 7-bit register address 87 | @param data pointer to byte array that will be sent to the LoRa concentrator 88 | @param size size of the transfer, in byte(s) 89 | @return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR) 90 | */ 91 | int lgw_spi_wb(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data, uint16_t size); 92 | 93 | /** 94 | @brief LoRa concentrator SPI burst (multiple-byte) read 95 | @param spi_target generic pointer to SPI target (implementation dependant) 96 | @param address 7-bit register address 97 | @param data pointer to byte array that will be written from the LoRa concentrator 98 | @param size size of the transfer, in byte(s) 99 | @return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR) 100 | */ 101 | int lgw_spi_rb(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data, uint16_t size); 102 | 103 | #endif 104 | 105 | /* --- EOF ------------------------------------------------------------------ */ 106 | -------------------------------------------------------------------------------- /libloragw/inc/loragw_sx125x.h: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech 8 | 9 | Description: SX125x radio registers and constant definitions 10 | 11 | License: Revised BSD License, see LICENSE.TXT file include in the project 12 | 13 | Maintainer: Michael Coracin 14 | */ 15 | #ifndef __SX125X_REGS_H__ 16 | #define __SX125X_REGS_H__ 17 | 18 | /* 19 | SX1257 frequency setting : 20 | F_register(24bit) = F_rf (Hz) / F_step(Hz) 21 | = F_rf (Hz) * 2^19 / F_xtal(Hz) 22 | = F_rf (Hz) * 2^19 / 32e6 23 | = F_rf (Hz) * 256/15625 24 | 25 | SX1255 frequency setting : 26 | F_register(24bit) = F_rf (Hz) / F_step(Hz) 27 | = F_rf (Hz) * 2^20 / F_xtal(Hz) 28 | = F_rf (Hz) * 2^20 / 32e6 29 | = F_rf (Hz) * 512/15625 30 | */ 31 | 32 | #define SX125x_TX_DAC_CLK_SEL 1 /* 0:int, 1:ext */ 33 | #define SX125x_TX_DAC_GAIN 2 /* 3:0, 2:-3, 1:-6, 0:-9 dBFS (default 2) */ 34 | #define SX125x_TX_MIX_GAIN 14 /* -38 + 2*TxMixGain dB (default 14) */ 35 | #define SX125x_TX_PLL_BW 1 /* 0:75, 1:150, 2:225, 3:300 kHz (default 3) */ 36 | #define SX125x_TX_ANA_BW 0 /* 17.5 / 2*(41-TxAnaBw) MHz (default 0) */ 37 | #define SX125x_TX_DAC_BW 5 /* 24 + 8*TxDacBw Nb FIR taps (default 2) */ 38 | #define SX125x_RX_LNA_GAIN 1 /* 1 to 6, 1 highest gain */ 39 | #define SX125x_RX_BB_GAIN 12 /* 0 to 15 , 15 highest gain */ 40 | #define SX125x_LNA_ZIN 1 /* 0:50, 1:200 Ohms (default 1) */ 41 | #define SX125x_RX_ADC_BW 7 /* 0 to 7, 2:100= 199901L 22 | #define _XOPEN_SOURCE 600 23 | #else 24 | #define _XOPEN_SOURCE 500 25 | #endif 26 | 27 | #include /* printf fprintf */ 28 | #include /* clock_nanosleep */ 29 | 30 | /* -------------------------------------------------------------------------- */ 31 | /* --- PRIVATE MACROS ------------------------------------------------------- */ 32 | 33 | #if DEBUG_AUX == 1 34 | #define DEBUG_MSG(str) fprintf(stderr, str) 35 | #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) 36 | #else 37 | #define DEBUG_MSG(str) 38 | #define DEBUG_PRINTF(fmt, args...) 39 | #endif 40 | 41 | /* -------------------------------------------------------------------------- */ 42 | /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ 43 | 44 | /* This implementation is POSIX-pecific and require a fix to be compatible with C99 */ 45 | #ifdef __MACH__ 46 | #include 47 | 48 | void wait_ms(unsigned long a) { 49 | usleep(1000*a); 50 | } 51 | 52 | #else 53 | 54 | void wait_ms(unsigned long a) { 55 | struct timespec dly; 56 | struct timespec rem; 57 | 58 | dly.tv_sec = a / 1000; 59 | dly.tv_nsec = ((long)a % 1000) * 1000000; 60 | 61 | DEBUG_PRINTF("NOTE dly: %ld sec %ld ns\n", dly.tv_sec, dly.tv_nsec); 62 | 63 | if((dly.tv_sec > 0) || ((dly.tv_sec == 0) && (dly.tv_nsec > 100000))) { 64 | clock_nanosleep(CLOCK_MONOTONIC, 0, &dly, &rem); 65 | DEBUG_PRINTF("NOTE remain: %ld sec %ld ns\n", rem.tv_sec, rem.tv_nsec); 66 | } 67 | return; 68 | } 69 | 70 | #endif 71 | 72 | 73 | /* --- EOF ------------------------------------------------------------------ */ 74 | -------------------------------------------------------------------------------- /libloragw/src/loragw_fpga.c: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Functions used to handle FPGA register access for LoRa concentrator. 11 | Registers are addressed by name. 12 | Multi-bytes registers are handled automatically. 13 | Read-modify-write is handled automatically. 14 | 15 | License: Revised BSD License, see LICENSE.TXT file include in the project 16 | Maintainer: Michael Coracin 17 | */ 18 | 19 | /* -------------------------------------------------------------------------- */ 20 | /* --- DEPENDANCIES --------------------------------------------------------- */ 21 | 22 | #include /* C99 types */ 23 | #include /* bool type */ 24 | #include /* printf fprintf */ 25 | 26 | #include "loragw_spi.h" 27 | #include "loragw_aux.h" 28 | #include "loragw_hal.h" 29 | #include "loragw_reg.h" 30 | #include "loragw_fpga.h" 31 | 32 | /* -------------------------------------------------------------------------- */ 33 | /* --- PRIVATE MACROS ------------------------------------------------------- */ 34 | 35 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 36 | #if DEBUG_REG == 1 37 | #define DEBUG_MSG(str) fprintf(stderr, str) 38 | #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) 39 | #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;} 40 | #else 41 | #define DEBUG_MSG(str) 42 | #define DEBUG_PRINTF(fmt, args...) 43 | #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;} 44 | #endif 45 | 46 | /* -------------------------------------------------------------------------- */ 47 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ 48 | 49 | /* 50 | auto generated register mapping for C code : 11-Jul-2013 13:20:40 51 | this file contains autogenerated C struct used to access the LoRa register from the Primer firmware 52 | this file is autogenerated from registers description 53 | 293 registers are defined 54 | */ 55 | const struct lgw_reg_s fpga_regs[LGW_FPGA_TOTALREGS] = { 56 | {-1,0,0,0,1,0,0}, /* SOFT_RESET */ 57 | {-1,0,1,0,7,1,0}, /* FPGA_FEATURE */ 58 | {-1,1,0,0,8,1,0}, /* VERSION */ 59 | {-1,2,0,0,8,1,0}, /* FPGA_STATUS */ 60 | {-1,3,0,0,1,0,0}, /* FPGA_CTRL_FEATURE_START */ 61 | {-1,3,1,0,1,0,0}, /* FPGA_CTRL_RADIO_RESET */ 62 | {-1,3,2,0,1,0,1}, /* FPGA_CTRL_INPUT_SYNC_I */ 63 | {-1,3,3,0,1,0,1}, /* FPGA_CTRL_INPUT_SYNC_Q */ 64 | {-1,3,4,0,1,0,0}, /* FPGA_CTRL_OUTPUT_SYNC */ 65 | {-1,3,5,0,1,0,1}, /* FPGA_CTRL_INVERT_IQ */ 66 | {-1,4,0,0,8,0,0}, /* HISTO_RAM_ADDR */ 67 | {-1,5,0,0,8,1,0}, /* HISTO_RAM_DATA */ 68 | {-1,6,0,0,16,0,32000}, /* HISTO_TEMPO */ 69 | {-1,8,0,0,16,0,1000}, /* HISTO_NB_READ */ 70 | {-1,10,0,0,32,1,0}, /* TIMESTAMP */ 71 | {-1,14,0,0,24,1,0}, /* LBT_TIMESTAMP_CH */ 72 | {-1,17,0,0,8,0,0}, /* LBT_TIMESTAMP_SELECT_CH */ 73 | {-1,18,0,0,8,0,8}, /* LBT_TIMESTAMP_NB_CH */ 74 | {-1,19,0,0,8,0,7}, /* SPI_MASTER_SPEED_DIVIDER */ 75 | {-1,20,0,0,8,0,10}, /* NB_READ_RSSI */ 76 | {-1,21,0,0,8,0,10}, /* PLL_LOCK_TIME */ 77 | {-1,22,0,0,8,0,160}, /* RSSI_TARGET */ 78 | {-1,23,0,0,16,0,0}, /* LSB_START_FREQ */ 79 | {-1,127,0,0,8,0,0} /* SPI_MUX_CTRL */ 80 | }; 81 | 82 | /* -------------------------------------------------------------------------- */ 83 | /* --- PRIVATE VARIABLES ---------------------------------------------------- */ 84 | 85 | extern void *lgw_spi_target; /*! generic pointer to the SPI device */ 86 | extern uint8_t lgw_spi_mux_mode; /*! current SPI mux mode used */ 87 | 88 | /* -------------------------------------------------------------------------- */ 89 | /* --- PRIVATE FUNCTIONS ---------------------------------------------------- */ 90 | 91 | /* -------------------------------------------------------------------------- */ 92 | /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ 93 | 94 | /* -------------------------------------------------------------------------- */ 95 | /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ 96 | 97 | int lgw_fpga_configure(void) { 98 | int x; 99 | int32_t val; 100 | bool tx_filter_support, spectral_scan_support, lbt_support; 101 | 102 | /* Get supported FPGA features */ 103 | printf("INFO: FPGA supported features:"); 104 | lgw_fpga_reg_r(LGW_FPGA_FPGA_FEATURE, &val); 105 | tx_filter_support = TAKE_N_BITS_FROM((uint8_t)val, 0, 1); 106 | if (tx_filter_support) { 107 | printf(" [TX filter] "); 108 | } 109 | spectral_scan_support = TAKE_N_BITS_FROM((uint8_t)val, 1, 1); 110 | if (spectral_scan_support) { 111 | printf(" [Spectral Scan] "); 112 | } 113 | lbt_support = TAKE_N_BITS_FROM((uint8_t)val, 2, 1); 114 | if (lbt_support) { 115 | printf(" [LBT] "); 116 | } 117 | printf("\n"); 118 | 119 | /* Configure TX filter */ 120 | x = lgw_fpga_reg_w(LGW_FPGA_CTRL_INPUT_SYNC_I, 0); 121 | x |= lgw_fpga_reg_w(LGW_FPGA_CTRL_INPUT_SYNC_Q, 0); 122 | x |= lgw_fpga_reg_w(LGW_FPGA_CTRL_OUTPUT_SYNC, 1); 123 | if( x != LGW_REG_SUCCESS ) 124 | { 125 | DEBUG_MSG("ERROR: Failed to configure FPGA TX filter\n"); 126 | return LGW_REG_ERROR; 127 | } 128 | 129 | return LGW_REG_SUCCESS; 130 | } 131 | 132 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 133 | 134 | /* Write to a register addressed by name */ 135 | int lgw_fpga_reg_w(uint16_t register_id, int32_t reg_value) { 136 | int spi_stat = LGW_SPI_SUCCESS; 137 | struct lgw_reg_s r; 138 | 139 | /* check input parameters */ 140 | if (register_id >= LGW_FPGA_TOTALREGS) { 141 | DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n"); 142 | return LGW_REG_ERROR; 143 | } 144 | 145 | /* check if SPI is initialised */ 146 | if (lgw_spi_target == NULL) { 147 | DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n"); 148 | return LGW_REG_ERROR; 149 | } 150 | 151 | /* get register struct from the struct array */ 152 | r = fpga_regs[register_id]; 153 | 154 | /* reject write to read-only registers */ 155 | if (r.rdon == 1){ 156 | DEBUG_MSG("ERROR: TRYING TO WRITE A READ-ONLY REGISTER\n"); 157 | return LGW_REG_ERROR; 158 | } 159 | 160 | spi_stat += reg_w_align32(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_FPGA, r, reg_value); 161 | 162 | if (spi_stat != LGW_SPI_SUCCESS) { 163 | DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER WRITE\n"); 164 | return LGW_REG_ERROR; 165 | } else { 166 | return LGW_REG_SUCCESS; 167 | } 168 | } 169 | 170 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 171 | 172 | /* Read to a register addressed by name */ 173 | int lgw_fpga_reg_r(uint16_t register_id, int32_t *reg_value) { 174 | int spi_stat = LGW_SPI_SUCCESS; 175 | struct lgw_reg_s r; 176 | 177 | /* check input parameters */ 178 | CHECK_NULL(reg_value); 179 | if (register_id >= LGW_FPGA_TOTALREGS) { 180 | DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n"); 181 | return LGW_REG_ERROR; 182 | } 183 | 184 | /* check if SPI is initialised */ 185 | if (lgw_spi_target == NULL) { 186 | DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n"); 187 | return LGW_REG_ERROR; 188 | } 189 | 190 | /* get register struct from the struct array */ 191 | r = fpga_regs[register_id]; 192 | 193 | spi_stat += reg_r_align32(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_FPGA, r, reg_value); 194 | 195 | if (spi_stat != LGW_SPI_SUCCESS) { 196 | DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER WRITE\n"); 197 | return LGW_REG_ERROR; 198 | } else { 199 | return LGW_REG_SUCCESS; 200 | } 201 | } 202 | 203 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 204 | 205 | /* Point to a register by name and do a burst write */ 206 | int lgw_fpga_reg_wb(uint16_t register_id, uint8_t *data, uint16_t size) { 207 | int spi_stat = LGW_SPI_SUCCESS; 208 | struct lgw_reg_s r; 209 | 210 | /* check input parameters */ 211 | CHECK_NULL(data); 212 | if (size == 0) { 213 | DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); 214 | return LGW_REG_ERROR; 215 | } 216 | if (register_id >= LGW_FPGA_TOTALREGS) { 217 | DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n"); 218 | return LGW_REG_ERROR; 219 | } 220 | 221 | /* check if SPI is initialised */ 222 | if (lgw_spi_target == NULL) { 223 | DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n"); 224 | return LGW_REG_ERROR; 225 | } 226 | 227 | /* get register struct from the struct array */ 228 | r = fpga_regs[register_id]; 229 | 230 | /* reject write to read-only registers */ 231 | if (r.rdon == 1){ 232 | DEBUG_MSG("ERROR: TRYING TO BURST WRITE A READ-ONLY REGISTER\n"); 233 | return LGW_REG_ERROR; 234 | } 235 | 236 | /* do the burst write */ 237 | spi_stat += lgw_spi_wb(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_FPGA, r.addr, data, size); 238 | 239 | if (spi_stat != LGW_SPI_SUCCESS) { 240 | DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST WRITE\n"); 241 | return LGW_REG_ERROR; 242 | } else { 243 | return LGW_REG_SUCCESS; 244 | } 245 | } 246 | 247 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 248 | 249 | /* Point to a register by name and do a burst read */ 250 | int lgw_fpga_reg_rb(uint16_t register_id, uint8_t *data, uint16_t size) { 251 | int spi_stat = LGW_SPI_SUCCESS; 252 | struct lgw_reg_s r; 253 | 254 | /* check input parameters */ 255 | CHECK_NULL(data); 256 | if (size == 0) { 257 | DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); 258 | return LGW_REG_ERROR; 259 | } 260 | if (register_id >= LGW_FPGA_TOTALREGS) { 261 | DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n"); 262 | return LGW_REG_ERROR; 263 | } 264 | 265 | /* check if SPI is initialised */ 266 | if (lgw_spi_target == NULL) { 267 | DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n"); 268 | return LGW_REG_ERROR; 269 | } 270 | 271 | /* get register struct from the struct array */ 272 | r = fpga_regs[register_id]; 273 | 274 | /* do the burst read */ 275 | spi_stat += lgw_spi_rb(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_FPGA, r.addr, data, size); 276 | 277 | if (spi_stat != LGW_SPI_SUCCESS) { 278 | DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST READ\n"); 279 | return LGW_REG_ERROR; 280 | } else { 281 | return LGW_REG_SUCCESS; 282 | } 283 | } 284 | 285 | /* --- EOF ------------------------------------------------------------------ */ 286 | -------------------------------------------------------------------------------- /libloragw/src/loragw_lbt.c: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Functions used to handle the Listen Before Talk feature 11 | 12 | License: Revised BSD License, see LICENSE.TXT file include in the project 13 | Maintainer: Michael Coracin 14 | */ 15 | 16 | /* -------------------------------------------------------------------------- */ 17 | /* --- DEPENDANCIES --------------------------------------------------------- */ 18 | 19 | #include /* C99 types */ 20 | #include /* bool type */ 21 | #include /* printf fprintf */ 22 | #include /* abs, labs, llabs */ 23 | 24 | #include "loragw_radio.h" 25 | #include "loragw_aux.h" 26 | #include "loragw_hal.h" 27 | #include "loragw_lbt.h" 28 | #include "loragw_fpga.h" 29 | 30 | /* -------------------------------------------------------------------------- */ 31 | /* --- PRIVATE MACROS ------------------------------------------------------- */ 32 | 33 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 34 | #if DEBUG_LBT == 1 35 | #define DEBUG_MSG(str) fprintf(stderr, str) 36 | #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) 37 | #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;} 38 | #else 39 | #define DEBUG_MSG(str) 40 | #define DEBUG_PRINTF(fmt, args...) 41 | #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;} 42 | #endif 43 | 44 | #define TX_START_DELAY 1500 45 | #define LBT_TIMESTAMP_MASK 0x007FFC00 46 | 47 | /* -------------------------------------------------------------------------- */ 48 | /* --- PRIVATE TYPES -------------------------------------------------------- */ 49 | 50 | /* -------------------------------------------------------------------------- */ 51 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ 52 | 53 | #define LBT_CHANNEL_FREQ_NB 10 /* Number of LBT channels */ 54 | #define LBT_CHANNEL_DELTA 200000 /* frequency delta between LBT channels, in Hz */ 55 | 56 | /* -------------------------------------------------------------------------- */ 57 | /* --- PRIVATE VARIABLES ---------------------------------------------------- */ 58 | 59 | extern void *lgw_spi_target; /*! generic pointer to the SPI device */ 60 | extern uint8_t lgw_spi_mux_mode; /*! current SPI mux mode used */ 61 | 62 | /* LBT variables shared with loragw_hal module */ 63 | bool lbt_enable; 64 | uint8_t lbt_rssi_target = 160; /* -80 dBm */ 65 | uint8_t lbt_nb_channel = 6; 66 | uint32_t lbt_first_channel_freq = 863000000; 67 | uint16_t lbt_scan_time_us = 220; 68 | 69 | /* LBT local variables */ 70 | static uint32_t lbt_end_tx_delay_1ch_us = 400000; 71 | static uint32_t lbt_end_tx_delay_2ch_us = 200000; 72 | static uint32_t lbt_channel_freq[LBT_CHANNEL_FREQ_NB]; /* absolute, in Hz */ 73 | 74 | /* -------------------------------------------------------------------------- */ 75 | /* --- PRIVATE FUNCTIONS ---------------------------------------------------- */ 76 | 77 | /* -------------------------------------------------------------------------- */ 78 | /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ 79 | 80 | /* As given frequencies have been converted from float to integer, some aliasing 81 | issues can appear, so we can't simply check for equality, but have to take some 82 | margin */ 83 | bool is_equal_freq(uint32_t a, uint32_t b) { 84 | int64_t diff; 85 | int64_t a64 = (int64_t)a; 86 | int64_t b64 = (int64_t)b; 87 | 88 | /* Calculate the difference */ 89 | diff = llabs(a64 - b64); 90 | 91 | /* Check for acceptable diff range */ 92 | if( diff <= 10000 ) 93 | { 94 | return true; 95 | } 96 | 97 | return false; 98 | } 99 | 100 | /* -------------------------------------------------------------------------- */ 101 | /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ 102 | 103 | int lbt_setconf(struct lgw_conf_lbt_s * conf) { 104 | int i; 105 | 106 | /* Check input parameters */ 107 | if (conf == NULL ) { 108 | return LGW_LBT_ERROR; 109 | } 110 | 111 | /* set internal config according to parameters */ 112 | lbt_enable = conf->enable; 113 | lbt_rssi_target = conf->rssi_target; 114 | lbt_scan_time_us = conf->scan_time_us; 115 | lbt_nb_channel = conf->nb_channel; 116 | lbt_end_tx_delay_1ch_us = conf->tx_delay_1ch_us; 117 | lbt_end_tx_delay_2ch_us = conf->tx_delay_2ch_us; 118 | lbt_first_channel_freq = conf->start_freq; 119 | 120 | /* set derivated parameters */ 121 | lbt_channel_freq[0] = lbt_first_channel_freq; 122 | for (i=1; imodulation != MOD_LORA) { 225 | *tx_allowed = false; 226 | DEBUG_PRINTF("INFO: TX is not allowed for this modulation (%x)\n", pkt_data->modulation); 227 | return LGW_LBT_SUCCESS; 228 | } 229 | 230 | /* Get current FPGA time */ 231 | lgw_fpga_reg_r(LGW_FPGA_TIMESTAMP, &val); 232 | fpga_time = (uint32_t)val; 233 | /* Get SX1301 time at last PPS */ 234 | lgw_get_trigcnt(&sx1301_time); 235 | 236 | DEBUG_MSG("################################\n"); 237 | switch(pkt_data->tx_mode) { 238 | case IMMEDIATE: 239 | DEBUG_MSG("tx_mode = IMMEDIATE\n"); 240 | tx_start_time = (fpga_time + TX_START_DELAY) & LBT_TIMESTAMP_MASK; /* 0x007FFC00: to align on LBT time format (TIMESTAMP_CH) */ 241 | break; 242 | case TIMESTAMPED: 243 | DEBUG_MSG("tx_mode = TIMESTAMPED\n"); 244 | tx_start_time = pkt_data->count_us & LBT_TIMESTAMP_MASK; 245 | break; 246 | case ON_GPS: 247 | DEBUG_MSG("tx_mode = ON_GPS\n"); 248 | tx_start_time = (sx1301_time + TX_START_DELAY + 1000000) & LBT_TIMESTAMP_MASK; 249 | break; 250 | default: 251 | return LGW_LBT_ERROR; 252 | } 253 | 254 | /* Select LBT Channel corresponding to required TX frequency */ 255 | if (pkt_data->bandwidth == BW_125KHZ){ 256 | tx_max_time = lbt_end_tx_delay_1ch_us; 257 | lbt_channel_decod_1 = -1; 258 | lbt_channel_decod_2 = -1; 259 | for (i=0; ifreq_hz, lbt_channel_freq[i]) == true) { 261 | DEBUG_PRINTF("LBT: select channel %d (%u Hz)\n", i, lbt_channel_freq[i]); 262 | lbt_channel_decod_1 = i; 263 | lbt_channel_decod_2 = i; 264 | break; 265 | } 266 | } 267 | } else if (pkt_data->bandwidth == BW_250KHZ) { 268 | tx_max_time = lbt_end_tx_delay_2ch_us; 269 | 270 | /* In case of 250KHz, the TX freq has to be in between 2 channels of 200KHz BW. The TX can only be over 2 channels, not more */ 271 | lbt_channel_decod_1 = -1; 272 | lbt_channel_decod_2 = -1; 273 | for (i=0; i<(LBT_CHANNEL_FREQ_NB-1); i++) { 274 | if (is_equal_freq(pkt_data->freq_hz, (lbt_channel_freq[i]+lbt_channel_freq[i+1])/2) == true) { 275 | DEBUG_PRINTF("LBT: select channels %d,%d (%u Hz)\n", i, i+1, (lbt_channel_freq[i]+lbt_channel_freq[i+1])/2); 276 | lbt_channel_decod_1 = i; 277 | lbt_channel_decod_2 = i+1; 278 | break; 279 | } 280 | } 281 | } else { 282 | lbt_channel_decod_1 = -1; 283 | lbt_channel_decod_2 = -1; 284 | } 285 | 286 | /* Get last time when selected channel was free */ 287 | if ((lbt_channel_decod_1 >= 0) && (lbt_channel_decod_2 >= 0)) { 288 | lgw_fpga_reg_w(LGW_FPGA_LBT_TIMESTAMP_SELECT_CH, (int32_t)lbt_channel_decod_1); 289 | lgw_fpga_reg_r(LGW_FPGA_LBT_TIMESTAMP_CH, &val); 290 | lbt_time = lbt_time1 = (uint32_t)(val & 0x00FFFFFF) * 256; /* 24bits (1LSB = 256µs) */ 291 | 292 | if (lbt_channel_decod_1 != lbt_channel_decod_2 ) { 293 | lgw_fpga_reg_w(LGW_FPGA_LBT_TIMESTAMP_SELECT_CH, (int32_t)lbt_channel_decod_2); 294 | lgw_fpga_reg_r(LGW_FPGA_LBT_TIMESTAMP_CH, &val); 295 | lbt_time2 = (uint32_t)(val & 0x00FFFFFF) * 256; /* 24bits (1LSB = 256µs) */ 296 | 297 | if (lbt_time2 < lbt_time1) { 298 | lbt_time = lbt_time2; 299 | } 300 | } 301 | } else { 302 | lbt_time = 0; 303 | } 304 | 305 | packet_duration = lgw_time_on_air(pkt_data, pkt_data->no_header) * 1000UL; 306 | tx_end_time = (tx_start_time + packet_duration) & LBT_TIMESTAMP_MASK; 307 | if (lbt_time < tx_end_time) { 308 | delta_time = tx_end_time - lbt_time; 309 | } else { 310 | /* It means LBT counter has wrapped */ 311 | printf("LBT: lbt counter has wrapped\n"); 312 | delta_time = (LBT_TIMESTAMP_MASK - lbt_time) + tx_end_time; 313 | } 314 | 315 | DEBUG_PRINTF("sx1301_time = %u\n", sx1301_time & LBT_TIMESTAMP_MASK); 316 | DEBUG_PRINTF("fpga_time = %u\n", fpga_time & LBT_TIMESTAMP_MASK); 317 | DEBUG_PRINTF("tx_freq = %u\n", pkt_data->freq_hz); 318 | DEBUG_MSG("------------------------------------------------\n"); 319 | DEBUG_PRINTF("packet_duration = %u\n", packet_duration); 320 | DEBUG_PRINTF("tx_start_time = %u\n", tx_start_time); 321 | DEBUG_PRINTF("lbt_time1 = %u\n", lbt_time1); 322 | DEBUG_PRINTF("lbt_time2 = %u\n", lbt_time2); 323 | DEBUG_PRINTF("lbt_time = %u\n", lbt_time); 324 | DEBUG_PRINTF("delta_time = %u\n", delta_time); 325 | DEBUG_MSG("------------------------------------------------\n"); 326 | 327 | /* send data if allowed */ 328 | /* lbt_time: last time when channel was free */ 329 | /* tx_max_time: maximum time allowed to send packet since last free time */ 330 | /* 2048: some margin */ 331 | if (((delta_time < (tx_max_time - 2048)) && (lbt_time != 0)) || (lbt_enable == false)) { 332 | *tx_allowed = true; 333 | } else { 334 | DEBUG_MSG("ERROR: TX request rejected (LBT)\n"); 335 | *tx_allowed = false; 336 | } 337 | } else { 338 | /* Always allow if LBT is disabled */ 339 | *tx_allowed = true; 340 | } 341 | 342 | return LGW_LBT_SUCCESS; 343 | } 344 | 345 | /* --- EOF ------------------------------------------------------------------ */ 346 | -------------------------------------------------------------------------------- /libloragw/src/loragw_spi.ftdi.c: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Host specific functions to address the LoRa concentrator registers through 11 | a SPI interface. 12 | Single-byte read/write and burst read/write. 13 | Does not handle pagination. 14 | Could be used with multiple SPI ports in parallel (explicit file descriptor) 15 | 16 | License: Revised BSD License, see LICENSE.TXT file include in the project 17 | Maintainer: Sylvain Miermont [support for ftdi was dropped from version 4.0.0 and onwards] 18 | Maintainer: Ruud Vlaming 19 | */ 20 | 21 | 22 | /* -------------------------------------------------------------------------- */ 23 | /* --- DEPENDANCIES --------------------------------------------------------- */ 24 | 25 | #include /* C99 types */ 26 | #include /* printf fprintf */ 27 | #include /* malloc free */ 28 | #include /* memcpy */ 29 | 30 | #include 31 | 32 | #include "loragw_spi.h" 33 | 34 | /* -------------------------------------------------------------------------- */ 35 | /* --- PRIVATE MACROS ------------------------------------------------------- */ 36 | 37 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 38 | #if DEBUG_SPI == 1 39 | #define DEBUG_MSG(str) fprintf(stderr, str) 40 | #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) 41 | #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_SPI_ERROR;} 42 | #else 43 | #define DEBUG_MSG(str) 44 | #define DEBUG_PRINTF(fmt, args...) 45 | #define CHECK_NULL(a) if(a==NULL){return LGW_SPI_ERROR;} 46 | #endif 47 | 48 | /* -------------------------------------------------------------------------- */ 49 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ 50 | 51 | #define READ_ACCESS 0x00 52 | #define WRITE_ACCESS 0x80 53 | 54 | /* -------------------------------------------------------------------------- */ 55 | /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ 56 | 57 | /* SPI initialization and configuration */ 58 | int lgw_spi_open(void **spi_target_ptr) { 59 | struct mpsse_context *mpsse = NULL; 60 | int a, b; 61 | 62 | /* check input variables */ 63 | CHECK_NULL(spi_target_ptr); /* cannot be null, must point on a void pointer (*spi_target_ptr can be null) */ 64 | 65 | /* try to open the first available FTDI device matching VID/PID parameters */ 66 | mpsse = OpenIndex(VID,PID,SPI0, SIX_MHZ, MSB, IFACE_A, NULL, NULL, 0); 67 | if (mpsse == NULL) { 68 | DEBUG_MSG("ERROR: MPSSE OPEN FUNCTION RETURNED NULL\n"); 69 | return LGW_SPI_ERROR; 70 | } 71 | if (mpsse->open != 1) { 72 | DEBUG_MSG("ERROR: MPSSE OPEN FUNCTION FAILED\n"); 73 | return LGW_SPI_ERROR; 74 | } 75 | 76 | #ifdef _MULTITECH_H_ 77 | /* toggle pin ADBUS5 of the FT232H */ 78 | /* On the MTAC LORA, it resets the SX1301 */ 79 | a = PinLow(mpsse, GPIOL1); 80 | b = PinHigh(mpsse, GPIOL1); 81 | #else 82 | /* toggle pin ADBUS5 of the FT2232H */ 83 | /* On the Semtech reference board, it resets the SX1301 */ 84 | a = PinHigh(mpsse, GPIOL1); 85 | b = PinLow(mpsse, GPIOL1); 86 | #endif 87 | if ((a != MPSSE_OK) || (b != MPSSE_OK)) { 88 | DEBUG_MSG("ERROR: IMPOSSIBLE TO TOGGLE GPIOL1/ADBUS5\n"); 89 | return LGW_SPI_ERROR; 90 | } 91 | 92 | DEBUG_PRINTF("SPI port opened and configured ok\ndesc: %s\nPID: 0x%04X\nVID: 0x%04X\nclock: %d\nLibmpsse version: 0x%02X\n", GetDescription(mpsse), GetPid(mpsse), GetVid(mpsse), GetClock(mpsse), Version()); 93 | *spi_target_ptr = (void *)mpsse; 94 | return LGW_SPI_SUCCESS; 95 | } 96 | 97 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 98 | 99 | /* SPI release */ 100 | int lgw_spi_close(void *spi_target) { 101 | struct mpsse_context *mpsse = spi_target; 102 | 103 | /* check input variables */ 104 | CHECK_NULL(spi_target); 105 | 106 | Close(mpsse); 107 | 108 | /* close return no status, assume success (0_o) */ 109 | return LGW_SPI_SUCCESS; 110 | } 111 | 112 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 113 | 114 | /* Simple write */ 115 | /* transaction time: .6 to 1 ms typically */ 116 | int lgw_spi_w(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t data) { 117 | struct mpsse_context *mpsse = spi_target; 118 | uint8_t out_buf[3]; 119 | uint8_t command_size; 120 | int a, b, c; 121 | 122 | /* check input variables */ 123 | CHECK_NULL(spi_target); 124 | if ((address & 0x80) != 0) { 125 | DEBUG_MSG("WARNING: SPI address > 127\n"); 126 | } 127 | 128 | /* prepare frame to be sent */ 129 | if (spi_mux_mode == LGW_SPI_MUX_MODE1) { 130 | out_buf[0] = spi_mux_target; 131 | out_buf[1] = WRITE_ACCESS | (address & 0x7F); 132 | out_buf[2] = data; 133 | command_size = 3; 134 | } else { 135 | out_buf[0] = WRITE_ACCESS | (address & 0x7F); 136 | out_buf[1] = data; 137 | command_size = 2; 138 | } 139 | 140 | /* MPSSE transaction */ 141 | a = Start(mpsse); 142 | b = FastWrite(mpsse, (char *)out_buf, command_size); 143 | c = Stop(mpsse); 144 | 145 | /* determine return code */ 146 | if ((a != MPSSE_OK) || (b != MPSSE_OK) || (c != MPSSE_OK)) { 147 | DEBUG_MSG("ERROR: SPI WRITE FAILURE\n"); 148 | return LGW_SPI_ERROR; 149 | } else { 150 | DEBUG_MSG("Note: SPI write success\n"); 151 | return LGW_SPI_SUCCESS; 152 | } 153 | } 154 | 155 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 156 | 157 | /* Simple read (using Transfer function) */ 158 | /* transaction time: 1.1 to 2 ms typically */ 159 | int lgw_spi_r(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data) { 160 | struct mpsse_context *mpsse = spi_target; 161 | uint8_t out_buf[3]; 162 | uint8_t command_size; 163 | uint8_t *in_buf = NULL; 164 | int a, b; 165 | 166 | /* check input variables */ 167 | CHECK_NULL(spi_target); 168 | if ((address & 0x80) != 0) { 169 | DEBUG_MSG("WARNING: SPI address > 127\n"); 170 | } 171 | CHECK_NULL(data); 172 | 173 | /* prepare frame to be sent */ 174 | if (spi_mux_mode == LGW_SPI_MUX_MODE1) { 175 | out_buf[0] = spi_mux_target; 176 | out_buf[1] = READ_ACCESS | (address & 0x7F); 177 | out_buf[2] = 0x00; 178 | command_size = 3; 179 | } else { 180 | out_buf[0] = READ_ACCESS | (address & 0x7F); 181 | out_buf[1] = 0x00; 182 | command_size = 2; 183 | } 184 | 185 | /* MPSSE transaction */ 186 | a = Start(mpsse); 187 | in_buf = (uint8_t *)Transfer(mpsse, (char *)out_buf, command_size); 188 | b = Stop(mpsse); 189 | 190 | /* determine return code */ 191 | if ((in_buf == NULL) || (a != MPSSE_OK) || (b != MPSSE_OK)) { 192 | DEBUG_MSG("ERROR: SPI READ FAILURE\n"); 193 | if (in_buf != NULL) { 194 | free(in_buf); 195 | } 196 | return LGW_SPI_ERROR; 197 | } else { 198 | DEBUG_MSG("Note: SPI read success\n"); 199 | *data = in_buf[1]; 200 | free(in_buf); 201 | return LGW_SPI_SUCCESS; 202 | } 203 | } 204 | 205 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 206 | 207 | /* Burst (multiple-byte) write */ 208 | /* transaction time: 3.7ms for 2500 data bytes @6MHz, 1kB chunks */ 209 | /* transaction time: 0.5ms for 16 data bytes @6MHz, 1kB chunks */ 210 | int lgw_spi_wb(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data, uint16_t size) { 211 | struct mpsse_context *mpsse = spi_target; 212 | uint8_t command[2]; 213 | uint8_t command_size; 214 | uint8_t *out_buf = NULL; 215 | int size_to_do, buf_size, chunk_size, offset; 216 | int a=0, b=0, c=0; 217 | int i; 218 | 219 | /* check input parameters */ 220 | CHECK_NULL(spi_target); 221 | if ((address & 0x80) != 0) { 222 | DEBUG_MSG("WARNING: SPI address > 127\n"); 223 | } 224 | CHECK_NULL(data); 225 | if (size == 0) { 226 | DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); 227 | return LGW_SPI_ERROR; 228 | } 229 | 230 | /* prepare command bytes */ 231 | if (spi_mux_mode == LGW_SPI_MUX_MODE1) { 232 | command[0] = spi_mux_target; 233 | command[1] = WRITE_ACCESS | (address & 0x7F); 234 | command_size = 2; 235 | } else { 236 | command[0] = WRITE_ACCESS | (address & 0x7F); 237 | command_size = 1; 238 | } 239 | size_to_do = size + command_size; /* add a byte for the address */ 240 | 241 | /* allocate data buffer */ 242 | buf_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; 243 | out_buf = malloc(buf_size); 244 | if (out_buf == NULL) { 245 | DEBUG_MSG("ERROR: MALLOC FAIL\n"); 246 | return LGW_SPI_ERROR; 247 | } 248 | 249 | /* start MPSSE transaction */ 250 | a = Start(mpsse); 251 | for (i=0; size_to_do > 0; ++i) { 252 | chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; 253 | if (i == 0) { 254 | /* first chunk, need to prepend the address */ 255 | memcpy(out_buf, command, command_size); 256 | memcpy(out_buf+command_size, data, chunk_size-command_size); 257 | } else { 258 | /* following chunks, just copy the data */ 259 | offset = (i * LGW_BURST_CHUNK) - command_size; 260 | memcpy(out_buf, data + offset, chunk_size); 261 | } 262 | b = FastWrite(mpsse, (char *)out_buf, chunk_size); 263 | size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ 264 | } 265 | c = Stop(mpsse); 266 | 267 | /* deallocate data buffer */ 268 | free(out_buf); 269 | 270 | /* determine return code (only the last FastWrite is checked) */ 271 | if ((a != MPSSE_OK) || (b != MPSSE_OK) || (c != MPSSE_OK)) { 272 | DEBUG_MSG("ERROR: SPI BURST WRITE FAILURE\n"); 273 | return LGW_SPI_ERROR; 274 | } else { 275 | DEBUG_MSG("Note: SPI burst write success\n"); 276 | return LGW_SPI_SUCCESS; 277 | } 278 | } 279 | 280 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 281 | 282 | /* Burst (multiple-byte) read (using FastWrite & FastRead functions) */ 283 | /* transaction time: 7-12ms for 2500 data bytes @6MHz, 1kB chunks */ 284 | /* transaction time: 2ms for 16 data bytes @6MHz, 1kB chunks */ 285 | int lgw_spi_rb(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data, uint16_t size) { 286 | struct mpsse_context *mpsse = spi_target; 287 | uint8_t command[2]; 288 | uint8_t command_size; 289 | int size_to_do, chunk_size, offset; 290 | int a=0, b=0, c=0, d=0; 291 | int i; 292 | 293 | /* check input parameters */ 294 | CHECK_NULL(spi_target); 295 | if ((address & 0x80) != 0) { 296 | DEBUG_MSG("WARNING: SPI address > 127\n"); 297 | } 298 | CHECK_NULL(data); 299 | if (size == 0) { 300 | DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); 301 | return LGW_SPI_ERROR; 302 | } 303 | 304 | /* prepare command bytes */ 305 | if (spi_mux_mode == LGW_SPI_MUX_MODE1) { 306 | command[0] = spi_mux_target; 307 | command[1] = READ_ACCESS | (address & 0x7F); 308 | command_size = 2; 309 | } else { 310 | command[0] = READ_ACCESS | (address & 0x7F); 311 | command_size = 1; 312 | } 313 | size_to_do = size; 314 | 315 | /* start MPSSE transaction */ 316 | a = Start(mpsse); 317 | b = FastWrite(mpsse, (char *)&command, command_size); 318 | for (i=0; size_to_do > 0; ++i) { 319 | chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; 320 | offset = i * LGW_BURST_CHUNK; 321 | c = FastRead(mpsse, (char *)(data + offset), chunk_size); 322 | size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ 323 | } 324 | d = Stop(mpsse); 325 | 326 | /* determine return code (only the last FastRead is checked) */ 327 | if ((a != MPSSE_OK) || (b != MPSSE_OK) || (c != MPSSE_OK) || (d != MPSSE_OK)) { 328 | DEBUG_MSG("ERROR: SPI BURST READ FAILURE\n"); 329 | return LGW_SPI_ERROR; 330 | } else { 331 | DEBUG_MSG("Note: SPI burst read success\n"); 332 | return LGW_SPI_SUCCESS; 333 | } 334 | } 335 | 336 | /* --- EOF ------------------------------------------------------------------ */ 337 | -------------------------------------------------------------------------------- /libloragw/src/loragw_spi.native.c: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Host specific functions to address the LoRa concentrator registers through 11 | a SPI interface. 12 | Single-byte read/write and burst read/write. 13 | Does not handle pagination. 14 | Could be used with multiple SPI ports in parallel (explicit file descriptor) 15 | 16 | License: Revised BSD License, see LICENSE.TXT file include in the project 17 | Maintainer: Sylvain Miermont 18 | */ 19 | 20 | 21 | /* -------------------------------------------------------------------------- */ 22 | /* --- DEPENDANCIES --------------------------------------------------------- */ 23 | 24 | #include /* C99 types */ 25 | #include /* printf fprintf */ 26 | #include /* malloc free */ 27 | #include /* lseek, close */ 28 | #include /* open */ 29 | #include /* memset */ 30 | 31 | #include 32 | #include 33 | 34 | #include "loragw_spi.h" 35 | #include "loragw_hal.h" 36 | 37 | /* -------------------------------------------------------------------------- */ 38 | /* --- PRIVATE MACROS ------------------------------------------------------- */ 39 | 40 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 41 | #if DEBUG_SPI == 1 42 | #define DEBUG_MSG(str) fprintf(stderr, str) 43 | #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) 44 | #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_SPI_ERROR;} 45 | #else 46 | #define DEBUG_MSG(str) 47 | #define DEBUG_PRINTF(fmt, args...) 48 | #define CHECK_NULL(a) if(a==NULL){return LGW_SPI_ERROR;} 49 | #endif 50 | 51 | /* -------------------------------------------------------------------------- */ 52 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ 53 | 54 | #define READ_ACCESS 0x00 55 | #define WRITE_ACCESS 0x80 56 | // This is handled in an other file to create more hardware freedom 57 | //#define SPI_SPEED 8000000 58 | //#define SPI_DEV_PATH "/dev/spidev0.0" 59 | //#define SPI_DEV_PATH "/dev/spidev32766.0" 60 | 61 | /* -------------------------------------------------------------------------- */ 62 | /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ 63 | 64 | /* SPI initialization and configuration */ 65 | int lgw_spi_open(void **spi_target_ptr) { 66 | int *spi_device = NULL; 67 | int dev; 68 | int a=0, b=0; 69 | int i; 70 | 71 | /* check input variables */ 72 | CHECK_NULL(spi_target_ptr); /* cannot be null, must point on a void pointer (*spi_target_ptr can be null) */ 73 | 74 | /* allocate memory for the device descriptor */ 75 | spi_device = malloc(sizeof(int)); 76 | if (spi_device == NULL) { 77 | DEBUG_MSG("ERROR: MALLOC FAIL\n"); 78 | return LGW_SPI_ERROR; 79 | } 80 | 81 | /* open SPI device */ 82 | dev = open(SPI_DEV_PATH, O_RDWR); 83 | if (dev < 0) { 84 | DEBUG_PRINTF("ERROR: failed to open SPI device %s\n", SPI_DEV_PATH); 85 | return LGW_SPI_ERROR; 86 | } 87 | 88 | /* setting SPI mode to 'mode 0' */ 89 | i = SPI_MODE_0; 90 | a = ioctl(dev, SPI_IOC_WR_MODE, &i); 91 | b = ioctl(dev, SPI_IOC_RD_MODE, &i); 92 | if ((a < 0) || (b < 0)) { 93 | DEBUG_MSG("ERROR: SPI PORT FAIL TO SET IN MODE 0\n"); 94 | close(dev); 95 | free(spi_device); 96 | return LGW_SPI_ERROR; 97 | } 98 | 99 | /* setting SPI max clk (in Hz) */ 100 | i = SPI_SPEED; 101 | a = ioctl(dev, SPI_IOC_WR_MAX_SPEED_HZ, &i); 102 | b = ioctl(dev, SPI_IOC_RD_MAX_SPEED_HZ, &i); 103 | if ((a < 0) || (b < 0)) { 104 | DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MAX SPEED\n"); 105 | close(dev); 106 | free(spi_device); 107 | return LGW_SPI_ERROR; 108 | } 109 | 110 | /* setting SPI to MSB first */ 111 | i = 0; 112 | a = ioctl(dev, SPI_IOC_WR_LSB_FIRST, &i); 113 | b = ioctl(dev, SPI_IOC_RD_LSB_FIRST, &i); 114 | if ((a < 0) || (b < 0)) { 115 | DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MSB FIRST\n"); 116 | close(dev); 117 | free(spi_device); 118 | return LGW_SPI_ERROR; 119 | } 120 | 121 | /* setting SPI to 8 bits per word */ 122 | i = 0; 123 | a = ioctl(dev, SPI_IOC_WR_BITS_PER_WORD, &i); 124 | b = ioctl(dev, SPI_IOC_RD_BITS_PER_WORD, &i); 125 | if ((a < 0) || (b < 0)) { 126 | DEBUG_MSG("ERROR: SPI PORT FAIL TO SET 8 BITS-PER-WORD\n"); 127 | close(dev); 128 | return LGW_SPI_ERROR; 129 | } 130 | 131 | *spi_device = dev; 132 | *spi_target_ptr = (void *)spi_device; 133 | DEBUG_MSG("Note: SPI port opened and configured ok\n"); 134 | return LGW_SPI_SUCCESS; 135 | } 136 | 137 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 138 | 139 | /* SPI release */ 140 | int lgw_spi_close(void *spi_target) { 141 | int spi_device; 142 | int a; 143 | 144 | /* check input variables */ 145 | CHECK_NULL(spi_target); 146 | 147 | /* close file & deallocate file descriptor */ 148 | spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ 149 | a = close(spi_device); 150 | free(spi_target); 151 | 152 | /* determine return code */ 153 | if (a < 0) { 154 | DEBUG_MSG("ERROR: SPI PORT FAILED TO CLOSE\n"); 155 | return LGW_SPI_ERROR; 156 | } else { 157 | DEBUG_MSG("Note: SPI port closed\n"); 158 | return LGW_SPI_SUCCESS; 159 | } 160 | } 161 | 162 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 163 | 164 | /* Simple write */ 165 | int lgw_spi_w(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t data) { 166 | int spi_device; 167 | uint8_t out_buf[3]; 168 | uint8_t command_size; 169 | struct spi_ioc_transfer k; 170 | int a; 171 | 172 | /* check input variables */ 173 | CHECK_NULL(spi_target); 174 | if ((address & 0x80) != 0) { 175 | DEBUG_MSG("WARNING: SPI address > 127\n"); 176 | } 177 | 178 | spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ 179 | 180 | /* prepare frame to be sent */ 181 | if (spi_mux_mode == LGW_SPI_MUX_MODE1) { 182 | out_buf[0] = spi_mux_target; 183 | out_buf[1] = WRITE_ACCESS | (address & 0x7F); 184 | out_buf[2] = data; 185 | command_size = 3; 186 | } else { 187 | out_buf[0] = WRITE_ACCESS | (address & 0x7F); 188 | out_buf[1] = data; 189 | command_size = 2; 190 | } 191 | 192 | /* I/O transaction */ 193 | memset(&k, 0, sizeof(k)); /* clear k */ 194 | k.tx_buf = (unsigned long) out_buf; 195 | k.len = command_size; 196 | k.speed_hz = SPI_SPEED; 197 | k.cs_change = 0; 198 | k.bits_per_word = 8; 199 | a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); 200 | 201 | /* determine return code */ 202 | if (a != (int)k.len) { 203 | DEBUG_MSG("ERROR: SPI WRITE FAILURE\n"); 204 | return LGW_SPI_ERROR; 205 | } else { 206 | DEBUG_MSG("Note: SPI write success\n"); 207 | return LGW_SPI_SUCCESS; 208 | } 209 | } 210 | 211 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 212 | 213 | /* Simple read */ 214 | int lgw_spi_r(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data) { 215 | int spi_device; 216 | uint8_t out_buf[3]; 217 | uint8_t command_size; 218 | uint8_t in_buf[ARRAY_SIZE(out_buf)]; 219 | struct spi_ioc_transfer k; 220 | int a; 221 | 222 | /* check input variables */ 223 | CHECK_NULL(spi_target); 224 | if ((address & 0x80) != 0) { 225 | DEBUG_MSG("WARNING: SPI address > 127\n"); 226 | } 227 | CHECK_NULL(data); 228 | 229 | spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ 230 | 231 | /* prepare frame to be sent */ 232 | if (spi_mux_mode == LGW_SPI_MUX_MODE1) { 233 | out_buf[0] = spi_mux_target; 234 | out_buf[1] = READ_ACCESS | (address & 0x7F); 235 | out_buf[2] = 0x00; 236 | command_size = 3; 237 | } else { 238 | out_buf[0] = READ_ACCESS | (address & 0x7F); 239 | out_buf[1] = 0x00; 240 | command_size = 2; 241 | } 242 | 243 | /* I/O transaction */ 244 | memset(&k, 0, sizeof(k)); /* clear k */ 245 | k.tx_buf = (unsigned long) out_buf; 246 | k.rx_buf = (unsigned long) in_buf; 247 | k.len = command_size; 248 | k.cs_change = 0; 249 | a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); 250 | 251 | /* determine return code */ 252 | if (a != (int)k.len) { 253 | DEBUG_MSG("ERROR: SPI READ FAILURE\n"); 254 | return LGW_SPI_ERROR; 255 | } else { 256 | DEBUG_MSG("Note: SPI read success\n"); 257 | *data = in_buf[command_size - 1]; 258 | return LGW_SPI_SUCCESS; 259 | } 260 | } 261 | 262 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 263 | 264 | /* Burst (multiple-byte) write */ 265 | int lgw_spi_wb(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data, uint16_t size) { 266 | int spi_device; 267 | uint8_t command[2]; 268 | uint8_t command_size; 269 | struct spi_ioc_transfer k[2]; 270 | int size_to_do, chunk_size, offset; 271 | int byte_transfered = 0; 272 | int i; 273 | 274 | /* check input parameters */ 275 | CHECK_NULL(spi_target); 276 | if ((address & 0x80) != 0) { 277 | DEBUG_MSG("WARNING: SPI address > 127\n"); 278 | } 279 | CHECK_NULL(data); 280 | if (size == 0) { 281 | DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); 282 | return LGW_SPI_ERROR; 283 | } 284 | 285 | spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ 286 | 287 | /* prepare command byte */ 288 | if (spi_mux_mode == LGW_SPI_MUX_MODE1) { 289 | command[0] = spi_mux_target; 290 | command[1] = WRITE_ACCESS | (address & 0x7F); 291 | command_size = 2; 292 | } else { 293 | command[0] = WRITE_ACCESS | (address & 0x7F); 294 | command_size = 1; 295 | } 296 | size_to_do = size; 297 | 298 | /* I/O transaction */ 299 | memset(&k, 0, sizeof(k)); /* clear k */ 300 | k[0].tx_buf = (unsigned long) &command[0]; 301 | k[0].len = command_size; 302 | k[0].cs_change = 0; 303 | k[1].cs_change = 0; 304 | for (i=0; size_to_do > 0; ++i) { 305 | chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; 306 | offset = i * LGW_BURST_CHUNK; 307 | k[1].tx_buf = (unsigned long)(data + offset); 308 | k[1].len = chunk_size; 309 | byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - k[0].len ); 310 | DEBUG_PRINTF("BURST WRITE: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered); 311 | size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ 312 | } 313 | 314 | /* determine return code */ 315 | if (byte_transfered != size) { 316 | DEBUG_MSG("ERROR: SPI BURST WRITE FAILURE\n"); 317 | return LGW_SPI_ERROR; 318 | } else { 319 | DEBUG_MSG("Note: SPI burst write success\n"); 320 | return LGW_SPI_SUCCESS; 321 | } 322 | } 323 | 324 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 325 | 326 | /* Burst (multiple-byte) read */ 327 | int lgw_spi_rb(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data, uint16_t size) { 328 | int spi_device; 329 | uint8_t command[2]; 330 | uint8_t command_size; 331 | struct spi_ioc_transfer k[2]; 332 | int size_to_do, chunk_size, offset; 333 | int byte_transfered = 0; 334 | int i; 335 | 336 | /* check input parameters */ 337 | CHECK_NULL(spi_target); 338 | if ((address & 0x80) != 0) { 339 | DEBUG_MSG("WARNING: SPI address > 127\n"); 340 | } 341 | CHECK_NULL(data); 342 | if (size == 0) { 343 | DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); 344 | return LGW_SPI_ERROR; 345 | } 346 | 347 | spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ 348 | 349 | /* prepare command byte */ 350 | if (spi_mux_mode == LGW_SPI_MUX_MODE1) { 351 | command[0] = spi_mux_target; 352 | command[1] = READ_ACCESS | (address & 0x7F); 353 | command_size = 2; 354 | } else { 355 | command[0] = READ_ACCESS | (address & 0x7F); 356 | command_size = 1; 357 | } 358 | size_to_do = size; 359 | 360 | /* I/O transaction */ 361 | memset(&k, 0, sizeof(k)); /* clear k */ 362 | k[0].tx_buf = (unsigned long) &command[0]; 363 | k[0].len = command_size; 364 | k[0].cs_change = 0; 365 | k[1].cs_change = 0; 366 | for (i=0; size_to_do > 0; ++i) { 367 | chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; 368 | offset = i * LGW_BURST_CHUNK; 369 | k[1].rx_buf = (unsigned long)(data + offset); 370 | k[1].len = chunk_size; 371 | byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - k[0].len ); 372 | DEBUG_PRINTF("BURST READ: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered); 373 | size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ 374 | } 375 | 376 | /* determine return code */ 377 | if (byte_transfered != size) { 378 | DEBUG_MSG("ERROR: SPI BURST READ FAILURE\n"); 379 | return LGW_SPI_ERROR; 380 | } else { 381 | DEBUG_MSG("Note: SPI burst read success\n"); 382 | return LGW_SPI_SUCCESS; 383 | } 384 | } 385 | 386 | /* --- EOF ------------------------------------------------------------------ */ 387 | -------------------------------------------------------------------------------- /libloragw/tst/test_loragw_gps.c: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Minimum test program for the loragw_gps 'library' 11 | 12 | License: Revised BSD License, see LICENSE.TXT file include in the project 13 | Maintainer: Sylvain Miermont 14 | */ 15 | 16 | 17 | /* -------------------------------------------------------------------------- */ 18 | /* --- DEPENDANCIES --------------------------------------------------------- */ 19 | 20 | /* fix an issue between POSIX and C99 */ 21 | #if __STDC_VERSION__ >= 199901L 22 | #define _XOPEN_SOURCE 600 23 | #else 24 | #define _XOPEN_SOURCE 500 25 | #endif 26 | 27 | #include /* C99 types */ 28 | #include /* bool type */ 29 | #include /* printf */ 30 | #include /* memset */ 31 | #include /* sigaction */ 32 | #include /* exit */ 33 | #include /* read */ 34 | 35 | #include "loragw_hal.h" 36 | #include "loragw_gps.h" 37 | #include "loragw_aux.h" 38 | 39 | /* -------------------------------------------------------------------------- */ 40 | /* --- PRIVATE VARIABLES ---------------------------------------------------- */ 41 | 42 | static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ 43 | static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */ 44 | 45 | /* -------------------------------------------------------------------------- */ 46 | /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ 47 | 48 | static void sig_handler(int sigio); 49 | 50 | /* -------------------------------------------------------------------------- */ 51 | /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ 52 | 53 | static void sig_handler(int sigio) { 54 | if (sigio == SIGQUIT) { 55 | quit_sig = 1;; 56 | } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { 57 | exit_sig = 1; 58 | } 59 | } 60 | 61 | /* -------------------------------------------------------------------------- */ 62 | /* --- MAIN FUNCTION -------------------------------------------------------- */ 63 | 64 | int main() 65 | { 66 | struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ 67 | 68 | int i; 69 | char tmp_str[80]; 70 | 71 | /* serial variables */ 72 | char serial_buff[128]; /* buffer to receive GPS data */ 73 | ssize_t nb_char; 74 | int gps_tty_dev; /* file descriptor to the serial port of the GNSS module */ 75 | 76 | /* NMEA variables */ 77 | enum gps_msg latest_msg; /* keep track of latest NMEA message parsed */ 78 | 79 | /* variables for PPM pulse GPS synchronization */ 80 | uint32_t ppm_tstamp; 81 | struct timespec ppm_utc; 82 | struct tref ppm_ref; 83 | 84 | /* variables for timestamp <-> UTC conversions */ 85 | uint32_t x, z; 86 | struct timespec y; 87 | 88 | /* configure signal handling */ 89 | sigemptyset(&sigact.sa_mask); 90 | sigact.sa_flags = 0; 91 | sigact.sa_handler = sig_handler; 92 | sigaction(SIGQUIT, &sigact, NULL); 93 | sigaction(SIGINT, &sigact, NULL); 94 | sigaction(SIGTERM, &sigact, NULL); 95 | 96 | /* Intro message and library information */ 97 | printf("Beginning of test for loragw_gps.c\n"); 98 | printf("*** Library version information ***\n%s\n***\n", lgw_version_info()); 99 | 100 | /* Open and configure GPS */ 101 | i = lgw_gps_enable("/dev/ttyAMA0", NULL, 0, &gps_tty_dev); 102 | if (i != LGW_GPS_SUCCESS) { 103 | printf("ERROR: IMPOSSIBLE TO ENABLE GPS\n"); 104 | exit(EXIT_FAILURE); 105 | } 106 | 107 | /* start concentrator */ 108 | lgw_start(); 109 | 110 | /* initialize some variables before loop */ 111 | memset(serial_buff, 0, sizeof serial_buff); 112 | memset(&ppm_ref, 0, sizeof ppm_ref); 113 | 114 | /* loop until user action */ 115 | while ((quit_sig != 1) && (exit_sig != 1)) { 116 | /* blocking canonical read on serial port */ 117 | nb_char = read(gps_tty_dev, serial_buff, sizeof(serial_buff)-1); 118 | if (nb_char <= 0) { 119 | printf("Warning: read() returned value <= 0\n"); 120 | continue; 121 | } else { 122 | serial_buff[nb_char] = 0; 123 | } 124 | 125 | /* parse the received NMEA */ 126 | latest_msg = lgw_parse_nmea(serial_buff, sizeof(serial_buff)); 127 | 128 | if (latest_msg == NMEA_RMC) { 129 | 130 | printf("\n~~ RMC NMEA sentence, triggering synchronization attempt ~~\n"); 131 | 132 | /* get UTC time for synchronization */ 133 | i = lgw_gps_get(&ppm_utc, NULL, NULL); 134 | if (i != LGW_GPS_SUCCESS) { 135 | printf(" No valid reference UTC time available, synchronization impossible.\n"); 136 | continue; 137 | } 138 | /* get timestamp for synchronization */ 139 | i = lgw_get_trigcnt(&ppm_tstamp); 140 | if (i != LGW_HAL_SUCCESS) { 141 | printf(" Failed to read timestamp, synchronization impossible.\n"); 142 | continue; 143 | } 144 | /* try to update synchronize time reference with the new UTC & timestamp */ 145 | i = lgw_gps_sync(&ppm_ref, ppm_tstamp, ppm_utc); 146 | if (i != LGW_GPS_SUCCESS) { 147 | printf(" Synchronization error.\n"); 148 | continue; 149 | } 150 | /* display result */ 151 | printf(" * Synchronization successful *\n"); 152 | strftime(tmp_str, sizeof(tmp_str), "%F %T", gmtime(&(ppm_ref.utc.tv_sec))); 153 | printf(" UTC reference time: %s.%09ldZ\n", tmp_str, ppm_ref.utc.tv_nsec); 154 | printf(" Internal counter reference value: %u\n", ppm_ref.count_us); 155 | printf(" Clock error: %.9f\n", ppm_ref.xtal_err); 156 | 157 | x = ppm_tstamp + 500000; 158 | printf(" * Test of timestamp counter <-> UTC value conversion *\n"); 159 | printf(" Test value: %u\n", x); 160 | lgw_cnt2utc(ppm_ref, x, &y); 161 | strftime(tmp_str, sizeof(tmp_str), "%F %T", gmtime(&(y.tv_sec))); 162 | printf(" Conversion to UTC: %s.%09ldZ\n", tmp_str, y.tv_nsec); 163 | lgw_utc2cnt(ppm_ref, y, &z); 164 | printf(" Converted back: %u\n", z); 165 | } 166 | } 167 | 168 | /* clean up before leaving */ 169 | if (exit_sig == 1) { 170 | lgw_stop(); 171 | } 172 | 173 | printf("\nEnd of test for loragw_gps.c\n"); 174 | exit(EXIT_SUCCESS); 175 | } 176 | 177 | /* --- EOF ------------------------------------------------------------------ */ 178 | -------------------------------------------------------------------------------- /libloragw/tst/test_loragw_reg.c: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Minimum test program for the loragw_spi 'library' 11 | 12 | License: Revised BSD License, see LICENSE.TXT file include in the project 13 | Maintainer: Sylvain Miermont 14 | */ 15 | 16 | 17 | /* -------------------------------------------------------------------------- */ 18 | /* --- DEPENDANCIES --------------------------------------------------------- */ 19 | 20 | #include 21 | #include 22 | 23 | #include "loragw_reg.h" 24 | 25 | /* -------------------------------------------------------------------------- */ 26 | /* --- MAIN FUNCTION -------------------------------------------------------- */ 27 | 28 | #define BURST_TEST_LENGTH 8192 29 | 30 | int main() 31 | { 32 | int32_t read_value, test_value; 33 | uint16_t lfsr; 34 | uint8_t burst_buffout[BURST_TEST_LENGTH]; 35 | uint8_t burst_buffin[BURST_TEST_LENGTH]; 36 | int i; 37 | 38 | printf("Beginning of test for loragw_reg.c\n"); 39 | 40 | lgw_connect(); 41 | /* 2 SPI transactions: 42 | -> 0x80 0x00 <- 0x00 0x00 forcing page 0 43 | -> 0x01 0x00 <- 0x00 0x64 checking version 44 | */ 45 | 46 | /* --- READ TEST --- */ 47 | 48 | lgw_reg_w(LGW_SOFT_RESET, 1); 49 | lgw_reg_check(stdout); 50 | 51 | /* --- READ/WRITE COHERENCY TEST --- */ 52 | 53 | /* 8b unsigned */ 54 | test_value = 197; /* 11000101b */ 55 | lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value); 56 | lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); 57 | printf("IMPLICIT_PAYLOAD_LENGHT = %d (should be %d)\n", read_value, test_value); 58 | 59 | /* 8b signed */ 60 | /* NO SUCH REG AVAILABLE */ 61 | // /* RADIO_SELECT is normally unsigned, modify it manually in loragw_reg.c */ 62 | // test_value = -59; /* 11000101b */ 63 | // lgw_reg_w(LGW_RADIO_SELECT, test_value); 64 | // lgw_reg_r(LGW_RADIO_SELECT, &read_value); 65 | // printf("RADIO_SELECT = %d (should be %d)\n", read_value, test_value); 66 | 67 | /* less than 8b, with offset, unsigned */ 68 | test_value = 11; /* 1011b */ 69 | lgw_reg_w(LGW_FRAME_SYNCH_PEAK2_POS, test_value); 70 | lgw_reg_r(LGW_FRAME_SYNCH_PEAK2_POS, &read_value); 71 | printf("FRAME_SYNCH_PEAK2_POS = %d (should be %d)\n", read_value, test_value); 72 | 73 | /* less than 8b, with offset, signed */ 74 | /* NO SUCH REG AVAILABLE */ 75 | // /* MBWSSF_FRAME_SYNCH_PEAK2_POS is normally unsigned, modify it manually in loragw_reg.c */ 76 | // test_value = -5; /* 1011b */ 77 | // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS, test_value); 78 | // lgw_reg_r(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS, &read_value); 79 | // printf("MBWSSF_FRAME_SYNCH_PEAK2_POS = %d (should be %d)\n", read_value, test_value); 80 | 81 | /* 16b unsigned */ 82 | test_value = 49253; /* 11000000 01100101b */ 83 | lgw_reg_w(LGW_PREAMBLE_SYMB1_NB, test_value); 84 | lgw_reg_r(LGW_PREAMBLE_SYMB1_NB, &read_value); 85 | printf("PREAMBLE_SYMB1_NB = %d (should be %d)\n", read_value, test_value); 86 | 87 | /* 16b signed */ 88 | /* NO SUCH REG AVAILABLE */ 89 | // /* CAPTURE_PERIOD is normally unsigned, modify it manually in loragw_reg.c */ 90 | // test_value = -16283; /* 11000000 01100101b */ 91 | // lgw_reg_w(LGW_CAPTURE_PERIOD, test_value); 92 | // lgw_reg_r(LGW_CAPTURE_PERIOD, &read_value); 93 | // printf("CAPTURE_PERIOD = %d (should be %d)\n", read_value, test_value); 94 | 95 | /* between 8b and 16b, unsigned */ 96 | test_value = 3173; /* 1100 01100101b */ 97 | lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4, test_value); 98 | lgw_reg_r(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4, &read_value); 99 | printf("ADJUST_MODEM_START_OFFSET_SF12_RDX4 = %d (should be %d)\n", read_value, test_value); 100 | 101 | /* between 8b and 16b, signed */ 102 | test_value = -1947; /* 11000 01100101b */ 103 | lgw_reg_w(LGW_IF_FREQ_1, test_value); 104 | lgw_reg_r(LGW_IF_FREQ_1, &read_value); 105 | printf("IF_FREQ_1 = %d (should be %d)\n", read_value, test_value); 106 | 107 | /* --- BURST WRITE AND READ TEST --- */ 108 | 109 | /* initialize data for SPI test */ 110 | lfsr = 0xFFFF; 111 | for(i=0; i> 4)); 113 | /* printf("%05d # 0x%04x 0x%02x\n", i, lfsr, burst_buffout[i]); */ 114 | lfsr = (lfsr & 1) ? ((lfsr >> 1) ^ 0x8679) : (lfsr >> 1); 115 | } 116 | 117 | lgw_reg_wb(LGW_TX_DATA_BUF_DATA, burst_buffout, 256); 118 | lgw_reg_rb(LGW_RX_DATA_BUF_DATA, burst_buffin, 256); 119 | 120 | /* impossible to check in software, 121 | RX_DATA_BUF_DATA is read-only, 122 | TX_DATA_BUF_DATA is write only, 123 | use a logic analyser */ 124 | 125 | /* --- END OF TEST --- */ 126 | 127 | lgw_disconnect(); 128 | /* no SPI transaction */ 129 | 130 | printf("End of test for loragw_reg.c\n"); 131 | return 0; 132 | } 133 | 134 | /* --- EOF ------------------------------------------------------------------ */ 135 | -------------------------------------------------------------------------------- /libloragw/tst/test_loragw_spi.c: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Minimum test program for the loragw_spi 'library' 11 | Use logic analyser to check the results. 12 | 13 | License: Revised BSD License, see LICENSE.TXT file include in the project 14 | Maintainer: Sylvain Miermont 15 | */ 16 | 17 | 18 | /* -------------------------------------------------------------------------- */ 19 | /* --- DEPENDANCIES --------------------------------------------------------- */ 20 | 21 | #include 22 | #include 23 | 24 | #include "loragw_spi.h" 25 | 26 | /* -------------------------------------------------------------------------- */ 27 | /* --- PRIVATE MACROS ------------------------------------------------------- */ 28 | 29 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 30 | 31 | /* -------------------------------------------------------------------------- */ 32 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ 33 | 34 | #define BURST_TEST_SIZE 2500 /* >> LGW_BURST_CHUNK */ 35 | #define TIMING_REPEAT 1 /* repeat transactions multiple times for timing characterisation */ 36 | 37 | /* -------------------------------------------------------------------------- */ 38 | /* --- MAIN FUNCTION -------------------------------------------------------- */ 39 | 40 | int main() 41 | { 42 | int i; 43 | void *spi_target = NULL; 44 | uint8_t data = 0; 45 | uint8_t dataout[BURST_TEST_SIZE]; 46 | uint8_t datain[BURST_TEST_SIZE]; 47 | uint8_t spi_mux_mode = LGW_SPI_MUX_MODE0; 48 | 49 | for (i = 0; i < BURST_TEST_SIZE; ++i) { 50 | dataout[i] = 0x30 + (i % 10); /* ASCCI code for 0 -> 9 */ 51 | datain[i] = 0x23; /* garbage data, to be overwritten by received data */ 52 | } 53 | 54 | printf("Beginning of test for loragw_spi.c\n"); 55 | lgw_spi_open(&spi_target); 56 | 57 | /* normal R/W test */ 58 | for (i = 0; i < TIMING_REPEAT; ++i) 59 | lgw_spi_w(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0xAA, 0x96); 60 | for (i = 0; i < TIMING_REPEAT; ++i) 61 | lgw_spi_r(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0x55, &data); 62 | 63 | /* burst R/W test, small bursts << LGW_BURST_CHUNK */ 64 | for (i = 0; i < TIMING_REPEAT; ++i) 65 | lgw_spi_wb(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0x55, dataout, 16); 66 | for (i = 0; i < TIMING_REPEAT; ++i) 67 | lgw_spi_rb(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0x55, datain, 16); 68 | 69 | /* burst R/W test, large bursts >> LGW_BURST_CHUNK */ 70 | for (i = 0; i < TIMING_REPEAT; ++i) 71 | lgw_spi_wb(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0x5A, dataout, ARRAY_SIZE(dataout)); 72 | for (i = 0; i < TIMING_REPEAT; ++i) 73 | lgw_spi_rb(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0x5A, datain, ARRAY_SIZE(datain)); 74 | 75 | /* last read (blocking), just to be sure no to quit before the FTDI buffer is flushed */ 76 | lgw_spi_r(spi_target, spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0x55, &data); 77 | printf("data received (simple read): %d\n",data); 78 | 79 | lgw_spi_close(spi_target); 80 | printf("End of test for loragw_spi.c\n"); 81 | 82 | return 0; 83 | } 84 | 85 | /* --- EOF ------------------------------------------------------------------ */ 86 | -------------------------------------------------------------------------------- /mac-howto: -------------------------------------------------------------------------------- 1 | It is possible to operate the IMST concentrator with USB connection directly from the USB port of a Mac. However, 2 | there are many pitfalls. Forgetting just one step usually results in nothing working. The tips below are for Yosemite, 3 | based on own experience. 4 | 5 | Main steps: 6 | 1) Install the FTDI drivers. 7 | 2) Install mpsse. 8 | 3) Compile the lora_gateway and packet_forwarder with the 'mac' setting. 9 | 4) Manually remove Apples FTDI-USB driver 10 | 11 | The details. 12 | 13 | 1) Installing the drivers should not be to great a problem. There are two possible roads 14 | here. One, download and instal from FTDI's website: http://www.ftdichip.com/Drivers/D2XX.htm 15 | (no experience) or use macports with 16 | $ sudo port install ftdi1 17 | 18 | 2) You need to download, compile and install mpsse libmpsse, on a suitable place: 19 | $ git clone https://github.com/devttys0/libmpsse 20 | 21 | The minimum change you need to make is add #include to the support.c file. 22 | Then (in src directory): 23 | $ ./configure --disable-python 24 | 25 | Now, in case you get some errors (most likely) try this: 26 | ./configure LDFLAGS=-L/opt/local/lib CFLAGS="-I/opt/local/include -I/opt/local/include/libftdi1" --disable-python 27 | 28 | If needed In Makefile.in change the lines with "install -D ..." to "install ..." 29 | 30 | Then (as long as no errors occur) 31 | $ make 32 | $ sudo mkdir -p /usr/local/include 33 | $ make install 34 | 35 | 3) Edit the lora_gateway/libloragw/library.cfg to set the following values: 36 | CFG_SPI= mac 37 | PLATFORM= lorank 38 | 39 | and then compile 40 | $ cd lora_gateway 41 | $ make all 42 | $ cd ../packet_forwarder 43 | $ make mac 44 | 45 | 4) Remove the ancient apple ftdi driver (this step is needed at least after each reboot) 46 | $ sudo kextunload /System/Library/Extensions/FTDIUSBSerialDriver.kext 47 | or perhaps 48 | $ sudo kextunload -b com.apple.driver.AppleUSBFTDI 49 | Note: I dunno if this all works with USB-C, Apple changed the driver model in 50 | Sierra considerably and libmpsse is very old, inspect what is running with: 51 | $ kextstat 52 | 53 | 5) Now you can try to contact the concentrator (connect it!) 54 | $ cd lora_gateway/libloragw 55 | $ ./test_loragw_reg 56 | 57 | This should give something like: 58 | +++MATCH+++ reg number 0 read: 0 (0) default: 0 (0) 59 | +++MATCH+++ reg number 1 read: 0 (0) default: 0 (0) 60 | +++MATCH+++ reg number 2 read: 103 (67) default: 103 (67) 61 | +++MATCH+++ reg number 3 read: 0 (0) default: 0 (0) 62 | ###MISMATCH### reg number 4 read: 196 (c4) default: 0 (0) 63 | +++MATCH+++ reg number 5 read: 0 (0) default: 0 (0) 64 | +++MATCH+++ reg number 6 read: 0 (0) default: 0 (0) 65 | etc. 66 | 67 | If you get 68 | Beginning of test for loragw_reg.c 69 | ERROR: CONCENTRATOR UNCONNECTED 70 | IMPLICIT_PAYLOAD_LENGHT = -472136177 (should be 197) 71 | FRAME_SYNCH_PEAK2_POS = -472136177 (should be 11) 72 | etc 73 | 74 | something is still wrong, retry it as root: 75 | $ sudo ./test_loragw_reg 76 | 77 | Note that a sleep of your computer may require a reboot and a subsequent unload 78 | of the driver to restore contact to the concentrator. 79 | 80 | In you got this far, configure the global and local confs in the polyforwarder directory 81 | (make sure it remains valid jsin!) and fire up the polyforwarder. The standard lora_pkt_fwd 82 | is not suited for ftdi. 83 | 84 | $ cd packet_forwarder/poly_pkt_fwd 85 | $ nano global_conf.json 86 | $ nano local_conf.json 87 | $ ./poly_pkt_fwd 88 | 89 | 90 | Good luck. 91 | Ruud Vlaming. 2016 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /reset_lgw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script is intended to be used on IoT Starter Kit platform only, it 4 | # performs the following actions: 5 | # - export/unpexort GPIO7 used to reset the SX1301 chip 6 | # 7 | # Usage examples: 8 | # ./reset_lgw.sh stop 9 | # ./reset_lgw.sh start 10 | 11 | # The reset pin of SX1301 is wired with RPi GPIO7 12 | IOT_SK_SX1301_RESET_PIN=7 13 | 14 | WAIT_GPIO() { 15 | sleep 0.1 16 | } 17 | 18 | iot_sk_init() { 19 | # setup GPIO 7 20 | echo "$IOT_SK_SX1301_RESET_PIN" > /sys/class/gpio/export; WAIT_GPIO 21 | 22 | # set GPIO 7 as output 23 | echo "out" > /sys/class/gpio/gpio$IOT_SK_SX1301_RESET_PIN/direction; WAIT_GPIO 24 | 25 | # write output for SX1301 reset 26 | echo "1" > /sys/class/gpio/gpio$IOT_SK_SX1301_RESET_PIN/value; WAIT_GPIO 27 | echo "0" > /sys/class/gpio/gpio$IOT_SK_SX1301_RESET_PIN/value; WAIT_GPIO 28 | 29 | # set GPIO 7 as input 30 | echo "in" > /sys/class/gpio/gpio$IOT_SK_SX1301_RESET_PIN/direction; WAIT_GPIO 31 | } 32 | 33 | iot_sk_term() { 34 | # cleanup GPIO 7 35 | if [ -d /sys/class/gpio/gpio$IOT_SK_SX1301_RESET_PIN ] 36 | then 37 | echo "$IOT_SK_SX1301_RESET_PIN" > /sys/class/gpio/unexport; WAIT_GPIO 38 | fi 39 | } 40 | 41 | case "$1" in 42 | start) 43 | iot_sk_term 44 | iot_sk_init 45 | ;; 46 | stop) 47 | iot_sk_term 48 | ;; 49 | *) 50 | echo "Usage: $0 {start|stop}" 51 | exit 1 52 | ;; 53 | esac 54 | 55 | exit 0 56 | -------------------------------------------------------------------------------- /util_lbt_test/Makefile: -------------------------------------------------------------------------------- 1 | ### Application-specific constants 2 | 3 | APP_NAME := util_lbt_test 4 | 5 | ### Environment constants 6 | 7 | LGW_PATH ?= ../libloragw 8 | ARCH ?= 9 | CROSS_COMPILE ?= 10 | 11 | ### External constant definitions 12 | 13 | include $(LGW_PATH)/library.cfg 14 | 15 | ### Constant symbols 16 | 17 | CC := $(CROSS_COMPILE)gcc 18 | AR := $(CROSS_COMPILE)ar 19 | 20 | CFLAGS=-O2 -Wall -Wextra -std=c99 -Iinc -I. 21 | 22 | OBJDIR = obj 23 | 24 | ### Constants for LoRa concentrator HAL library 25 | # List the library sub-modules that are used by the application 26 | 27 | LGW_INC = $(LGW_PATH)/inc/config.h 28 | LGW_INC += $(LGW_PATH)/inc/loragw_reg.h 29 | LGW_INC += $(LGW_PATH)/inc/loragw_fpga.h 30 | 31 | ### Linking options 32 | 33 | ifeq ($(CFG_SPI),native) 34 | LIBS := -lloragw -lrt -lm 35 | else ifeq ($(CFG_SPI),ftdi) 36 | LIBS := -lloragw -lrt -lmpsse -lm 37 | else ifeq ($(CFG_SPI),mac) 38 | LIBS := -lloragw -lmpsse -lm 39 | endif 40 | 41 | ### General build targets 42 | 43 | all: $(APP_NAME) 44 | 45 | clean: 46 | rm -f $(OBJDIR)/*.o 47 | rm -f $(APP_NAME) 48 | 49 | ### HAL library (do no force multiple library rebuild even with 'make -B') 50 | 51 | $(LGW_PATH)/inc/config.h: 52 | @if test ! -f $@; then \ 53 | $(MAKE) all -C $(LGW_PATH); \ 54 | fi 55 | 56 | $(LGW_PATH)/libloragw.a: $(LGW_INC) 57 | @if test ! -f $@; then \ 58 | $(MAKE) all -C $(LGW_PATH); \ 59 | fi 60 | 61 | ### Main program compilation and assembly 62 | $(OBJDIR): 63 | mkdir -p $(OBJDIR) 64 | 65 | $(OBJDIR)/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) | $(OBJDIR) 66 | $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@ 67 | 68 | $(APP_NAME): $(OBJDIR)/$(APP_NAME).o $(LGW_PATH)/libloragw.a 69 | $(CC) -L$(LGW_PATH) $< -o $@ $(LIBS) 70 | 71 | ### EOF 72 | -------------------------------------------------------------------------------- /util_lbt_test/readme.md: -------------------------------------------------------------------------------- 1 | / _____) _ | | 2 | ( (____ _____ ____ _| |_ _____ ____| |__ 3 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 4 | _____) ) ____| | | || |_| ____( (___| | | | 5 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 6 | ©2013 Semtech-Cycleo 7 | 8 | Lora Gateway LBT basic test application 9 | ======================================= 10 | 11 | 1. Introduction 12 | ---------------- 13 | 14 | This software configures the FPGA for "Liste-Before-Talk" feature and 15 | continuously reads the LBT channels timestamps which indicate when was the last 16 | instant when the channel was free. 17 | 18 | 2. Dependencies 19 | ---------------- 20 | 21 | - A SX1301AP2 Ref Design board with its FPGA programmed with LBT feature 22 | 23 | 3. Usage 24 | --------- 25 | 26 | Before running the util_lbt_test application, the concentrator MUST be first 27 | started with the HAL, using for example util_pkt_logger or the packet forwarder. 28 | 29 | For a description of the command line options available: 30 | ./util_lbt_test -h 31 | 32 | ex: 33 | ./util_lbt_test -f 867.1 -t 100 -n 14 -s 15 -p 50 -r 162 34 | 35 | This will set 6 LBT channels, starting from 867.1 MHz, then each subsequent 36 | channel being set to the frequency of the previous channel +200 KHz (867.3, 37 | 867.5, ...). 38 | 39 | The above test will run for 100 iterations, with a CHANNEL_SCAN_TIME of 270µs 40 | and a target RSSI of -81dBm. 41 | 42 | Please refer to the lora_gateway library readme.md to get more details on the 43 | LBT feature implementation and configuration. 44 | 45 | 4. Changelog 46 | ------------- 47 | 48 | 2016-03-03 v1.0 Initial version 49 | -------------------------------------------------------------------------------- /util_lbt_test/src/util_lbt_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Listen Before Talk basic test application 11 | 12 | License: Revised BSD License, see LICENSE.TXT file include in the project 13 | Maintainer: Michael Coracinlibloragw/install_ftdi.txt 14 | */ 15 | 16 | 17 | /* -------------------------------------------------------------------------- */ 18 | /* --- DEPENDANCIES --------------------------------------------------------- */ 19 | 20 | /* fix an issue between POSIX and C99 */ 21 | #ifdef __MACH__ 22 | #elif __STDC_VERSION__ >= 199901L 23 | #define _XOPEN_SOURCE 600 24 | #else 25 | #define _XOPEN_SOURCE 500 26 | #endif 27 | 28 | #include /* C99 types */ 29 | #include /* bool type */ 30 | #include /* printf fprintf sprintf fopen fputs */ 31 | 32 | #include /* sigaction */ 33 | #include /* getopt access */ 34 | #include /* rand */ 35 | 36 | #include "loragw_aux.h" 37 | #include "loragw_reg.h" 38 | #include "loragw_hal.h" 39 | #include "loragw_radio.h" 40 | #include "loragw_fpga.h" 41 | 42 | /* -------------------------------------------------------------------------- */ 43 | /* --- PRIVATE MACROS ------------------------------------------------------- */ 44 | 45 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 46 | #define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */ 47 | 48 | /* -------------------------------------------------------------------------- */ 49 | /* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ 50 | 51 | /* signal handling variables */ 52 | struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ 53 | static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ 54 | static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */ 55 | 56 | /* -------------------------------------------------------------------------- */ 57 | /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ 58 | 59 | static void sig_handler(int sigio); 60 | 61 | void usage (void); 62 | 63 | /* -------------------------------------------------------------------------- */ 64 | /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ 65 | 66 | static void sig_handler(int sigio) { 67 | if (sigio == SIGQUIT) { 68 | quit_sig = 1;; 69 | } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { 70 | exit_sig = 1; 71 | } 72 | } 73 | 74 | /* describe command line options */ 75 | void usage(void) { 76 | printf( "Available options:\n"); 77 | printf( " -h print this help\n"); 78 | printf( " -f start frequency in MHz\n"); 79 | printf( " -t number of read loops [1..32000]\n"); 80 | printf( " -n number of spi access to SX127x RSSI instant register [0..255]\n"); 81 | printf( " -s spi speed divider [0..255]\n"); 82 | printf( " -p pll lock time: delay in 8 µsec step between frequency programming and RX ready [0..255]\n"); 83 | printf( " -r target RSSI: signal strength target used to detect if the channel is clear or not [0..255]\n"); 84 | } 85 | 86 | /* -------------------------------------------------------------------------- */ 87 | /* --- MAIN FUNCTION -------------------------------------------------------- */ 88 | 89 | int main(int argc, char **argv) 90 | { 91 | int i; 92 | int xi = 0; 93 | 94 | /* in/out variables */ 95 | double f1 = 0.0; 96 | uint32_t f_start = 0; /* in Hz */ 97 | uint16_t loop_cnt = 0; 98 | uint16_t tempo = 100; 99 | uint16_t nb_point = 14; 100 | uint8_t spi_speed_div = 15; 101 | uint8_t rssi_target = 162; 102 | uint8_t pll_lock_time = 50; 103 | uint16_t lsb_start_freq_int; 104 | uint32_t timestamp; 105 | uint8_t rssi_value; 106 | int32_t val; 107 | int channel; 108 | 109 | /* parse command line options */ 110 | while ((i = getopt (argc, argv, "h:f:t:n:s:p:r:o:")) != -1) { 111 | switch (i) { 112 | case 'h': 113 | usage(); 114 | return EXIT_FAILURE; 115 | break; 116 | 117 | case 'f': 118 | i = sscanf(optarg, "%lf", &f1); 119 | if ((i != 1) || (f1 < 30.0) || (f1 > 3000.0)) { 120 | MSG("ERROR: Invalid LBT start frequency\n"); 121 | usage(); 122 | return EXIT_FAILURE; 123 | } else { 124 | f_start = (uint32_t)((f1*1e6) + 0.5);/* .5 Hz offset to get rounding instead of truncating */ 125 | } 126 | break; 127 | case 't': 128 | i = sscanf(optarg, "%i", &xi); 129 | if ((i != 1) || (xi < 1) || (xi > 32000)) { 130 | MSG("ERROR: tempo must be b/w 1 & 32000 \n"); 131 | usage(); 132 | return EXIT_FAILURE; 133 | } else { 134 | tempo = xi; 135 | } 136 | break; 137 | case 'n': 138 | i = sscanf(optarg, "%i", &xi); 139 | if ((i != 1) || (xi < 0) || (xi > 255)) { 140 | MSG("ERROR: nb_point must be b/w 0 & 255 \n"); 141 | usage(); 142 | return EXIT_FAILURE; 143 | } else { 144 | nb_point = xi; 145 | } 146 | break; 147 | case 's': 148 | i = sscanf(optarg, "%i", &xi); 149 | if ((i != 1) || (xi < 0) || (xi > 255)) { 150 | MSG("ERROR: spi_speed_div must be b/w 0 & 255 \n"); 151 | usage(); 152 | return EXIT_FAILURE; 153 | } else { 154 | spi_speed_div = xi; 155 | } 156 | break; 157 | case 'r': 158 | i = sscanf(optarg, "%i", &xi); 159 | if ((i != 1) || (xi < 0) || (xi > 255)) { 160 | MSG("ERROR: rssi_target must be b/w 0 & 255 \n"); 161 | usage(); 162 | return EXIT_FAILURE; 163 | } else { 164 | rssi_target = xi; 165 | } 166 | break; 167 | case 'p': 168 | i = sscanf(optarg, "%i", &xi); 169 | if ((i != 1) || (xi < 0) || (xi > 255)) { 170 | MSG("ERROR: pll_lock_time must be b/w 1 & 256 \n"); 171 | usage(); 172 | return EXIT_FAILURE; 173 | } else { 174 | pll_lock_time = xi; 175 | } 176 | break; 177 | default: 178 | MSG("ERROR: argument parsing use -h option for help\n"); 179 | usage(); 180 | return EXIT_FAILURE; 181 | } 182 | } 183 | 184 | /* Sanity check */ 185 | if (f_start == 0) { 186 | MSG("ERROR: LBT start frequency must be set\n"); 187 | usage(); 188 | return EXIT_FAILURE; 189 | } 190 | 191 | MSG("INFO: Starting LoRa Gateway v1.5 LBT test\n"); 192 | 193 | /* configure signal handling */ 194 | sigemptyset(&sigact.sa_mask); 195 | sigact.sa_flags = 0; 196 | sigact.sa_handler = sig_handler; 197 | sigaction(SIGQUIT, &sigact, NULL); 198 | sigaction(SIGINT, &sigact, NULL); 199 | sigaction(SIGTERM, &sigact, NULL); 200 | 201 | /* Connect to concentrator */ 202 | i = lgw_connect(); 203 | if (i != LGW_REG_SUCCESS) { 204 | MSG("ERROR: lgw_connect() did not return SUCCESS\n"); 205 | return EXIT_FAILURE; 206 | } 207 | 208 | /* Check if FPGA supports LBT */ 209 | lgw_fpga_reg_r(LGW_FPGA_FPGA_FEATURE, &val); 210 | if (TAKE_N_BITS_FROM((uint8_t)val, 2, 1) != true) { 211 | printf("ERROR: LBT is not supported (0x%x)\n", (uint8_t)val); 212 | return EXIT_FAILURE; 213 | } 214 | 215 | MSG("FREQ: %u\n", f_start); 216 | 217 | /* Configure SX127x and read few RSSI points */ 218 | lgw_setup_sx127x(f_start, MOD_FSK); 219 | for (i = 0; i < 100; i++) { 220 | lgw_sx127x_reg_r(0x11, &rssi_value); /* 0x11: RegRssiValue */ 221 | MSG("SX127x RSSI:-%u dBm\n", rssi_value>>1); 222 | wait_ms(10); 223 | } 224 | 225 | /* Configure LBT */ 226 | lgw_fpga_reg_w(LGW_FPGA_SPI_MASTER_SPEED_DIVIDER, (int32_t)spi_speed_div); 227 | lgw_fpga_reg_w(LGW_FPGA_NB_READ_RSSI, (int32_t)nb_point); 228 | lgw_fpga_reg_w(LGW_FPGA_PLL_LOCK_TIME, (int32_t)pll_lock_time); 229 | lgw_fpga_reg_w(LGW_FPGA_RSSI_TARGET, (int32_t)rssi_target); 230 | lsb_start_freq_int = (((uint64_t)f_start<<19)/(uint64_t)32000000); 231 | lgw_fpga_reg_w(LGW_FPGA_LSB_START_FREQ, (int32_t)lsb_start_freq_int); 232 | lgw_fpga_reg_w(LGW_FPGA_LBT_TIMESTAMP_NB_CH, (6-1)); /* 6 channels */ 233 | 234 | /* Enable LBT FSM */ 235 | lgw_fpga_reg_w(LGW_FPGA_CTRL_FEATURE_START, 1); 236 | 237 | /* Read back LBT config */ 238 | lgw_fpga_reg_r(LGW_FPGA_SPI_MASTER_SPEED_DIVIDER, &val); 239 | MSG("spi_speed_div = %d\n", val); 240 | if (val != spi_speed_div) { 241 | return EXIT_FAILURE; 242 | } 243 | lgw_fpga_reg_r(LGW_FPGA_NB_READ_RSSI, &val); 244 | MSG("nb_point = %d\n", val); 245 | if (val != nb_point) { 246 | return EXIT_FAILURE; 247 | } 248 | lgw_fpga_reg_r(LGW_FPGA_PLL_LOCK_TIME, &val); 249 | MSG("PLL_LOCK = %d\n", val); 250 | if (val != pll_lock_time) { 251 | return EXIT_FAILURE; 252 | } 253 | lgw_fpga_reg_r(LGW_FPGA_RSSI_TARGET, &val); 254 | MSG("RSSI_TARGET = %d\n", val); 255 | if (val != rssi_target) { 256 | return EXIT_FAILURE; 257 | } 258 | lgw_fpga_reg_r(LGW_FPGA_VERSION, &val); 259 | MSG("FPGA VERSION = %d\n", val); 260 | 261 | /* Start test */ 262 | while (((quit_sig != 1) && (exit_sig != 1)) && (loop_cnt != tempo)) { 263 | /* Get current FPGA timestamp (1MHz) */ 264 | lgw_fpga_reg_r(LGW_FPGA_TIMESTAMP, &val); 265 | timestamp = (uint32_t)val; 266 | MSG(" TIMESTAMP = %u\n", timestamp); 267 | 268 | for (channel = 0; channel <= 5; channel++) { 269 | /* Select LBT channel */ 270 | lgw_fpga_reg_w(LGW_FPGA_LBT_TIMESTAMP_SELECT_CH, channel); 271 | 272 | /* Get last instant when the selected channel was free */ 273 | lgw_fpga_reg_r(LGW_FPGA_LBT_TIMESTAMP_CH, &val); 274 | timestamp = (uint32_t)(val & 0x00FFFFFF) * 256; /* 24bits (1LSB = 256µs) */ 275 | MSG(" TIMESTAMP_CH%u = %u\n", channel, timestamp); 276 | } 277 | 278 | loop_cnt += 1; 279 | wait_ms(400); 280 | } 281 | 282 | /* close SPI link */ 283 | i = lgw_disconnect(); 284 | if (i != LGW_REG_SUCCESS) { 285 | MSG("ERROR: lgw_disconnect() did not return SUCCESS\n"); 286 | return EXIT_FAILURE; 287 | } 288 | 289 | MSG("INFO: Exiting LoRa Gateway v1.5 LBT test successfully\n"); 290 | return EXIT_SUCCESS; 291 | } 292 | 293 | /* --- EOF ------------------------------------------------------------------ */ 294 | 295 | -------------------------------------------------------------------------------- /util_pkt_logger/Makefile: -------------------------------------------------------------------------------- 1 | ### Application-specific constants 2 | 3 | APP_NAME := util_pkt_logger 4 | 5 | ### Environment constants 6 | 7 | LGW_PATH ?= ../libloragw 8 | ARCH ?= 9 | CROSS_COMPILE ?= 10 | 11 | ### External constant definitions 12 | 13 | include $(LGW_PATH)/library.cfg 14 | 15 | ### Constant symbols 16 | 17 | CC := $(CROSS_COMPILE)gcc 18 | AR := $(CROSS_COMPILE)ar 19 | 20 | CFLAGS=-O2 -Wall -Wextra -std=c99 -Iinc -I. 21 | 22 | OBJDIR = obj 23 | 24 | ### Constants for LoRa concentrator HAL library 25 | # List the library sub-modules that are used by the application 26 | 27 | LGW_INC = $(LGW_PATH)/inc/config.h 28 | LGW_INC += $(LGW_PATH)/inc/loragw_hal.h 29 | 30 | ### Linking options 31 | 32 | ifeq ($(CFG_SPI),native) 33 | LIBS := -lloragw -lrt -lm 34 | else ifeq ($(CFG_SPI),ftdi) 35 | LIBS := -lloragw -lrt -lmpsse -lm 36 | else ifeq ($(CFG_SPI),mac) 37 | LIBS := -lloragw -lmpsse -lm 38 | endif 39 | 40 | ### General build targets 41 | 42 | all: $(APP_NAME) 43 | 44 | clean: 45 | rm -f $(OBJDIR)/*.o 46 | rm -f $(APP_NAME) 47 | 48 | ### HAL library (do no force multiple library rebuild even with 'make -B') 49 | 50 | $(LGW_PATH)/inc/config.h: 51 | @if test ! -f $@; then \ 52 | $(MAKE) all -C $(LGW_PATH); \ 53 | fi 54 | 55 | $(LGW_PATH)/libloragw.a: $(LGW_INC) 56 | @if test ! -f $@; then \ 57 | $(MAKE) all -C $(LGW_PATH); \ 58 | fi 59 | 60 | ### Sub-modules compilation 61 | 62 | $(OBJDIR): 63 | mkdir -p $(OBJDIR) 64 | 65 | $(OBJDIR)/parson.o: src/parson.c inc/parson.h | $(OBJDIR) 66 | $(CC) -c $(CFLAGS) $< -o $@ 67 | 68 | ### Main program compilation and assembly 69 | 70 | $(OBJDIR)/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) inc/parson.h | $(OBJDIR) 71 | $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@ 72 | 73 | $(APP_NAME): $(OBJDIR)/$(APP_NAME).o $(LGW_PATH)/libloragw.a $(OBJDIR)/parson.o 74 | $(CC) -L$(LGW_PATH) $< $(OBJDIR)/parson.o -o $@ $(LIBS) 75 | 76 | ### EOF 77 | -------------------------------------------------------------------------------- /util_pkt_logger/global_conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "SX1301_conf": { 3 | "lorawan_public": true, 4 | "clksrc": 1, /* radio_1 provides clock to concentrator */ 5 | "radio_0": { 6 | "enable": true, 7 | "type": "SX1257", 8 | "freq": 867500000, 9 | "rssi_offset": -166.0, 10 | "tx_enable": true 11 | }, 12 | "radio_1": { 13 | "enable": true, 14 | "type": "SX1257", 15 | "freq": 868500000, 16 | "rssi_offset": -166.0, 17 | "tx_enable": false 18 | }, 19 | "chan_multiSF_0": { 20 | /* Lora MAC channel, 125kHz, all SF, 868.1 MHz */ 21 | "enable": true, 22 | "radio": 1, 23 | "if": -400000 24 | }, 25 | "chan_multiSF_1": { 26 | /* Lora MAC channel, 125kHz, all SF, 868.3 MHz */ 27 | "enable": true, 28 | "radio": 1, 29 | "if": -200000 30 | }, 31 | "chan_multiSF_2": { 32 | /* Lora MAC channel, 125kHz, all SF, 868.5 MHz */ 33 | "enable": true, 34 | "radio": 1, 35 | "if": 0 36 | }, 37 | "chan_multiSF_3": { 38 | /* Lora MAC channel, 125kHz, all SF, 867.1 MHz */ 39 | "enable": true, 40 | "radio": 0, 41 | "if": -400000 42 | }, 43 | "chan_multiSF_4": { 44 | /* Lora MAC channel, 125kHz, all SF, 867.3 MHz */ 45 | "enable": true, 46 | "radio": 0, 47 | "if": -200000 48 | }, 49 | "chan_multiSF_5": { 50 | /* Lora MAC channel, 125kHz, all SF, 867.5 MHz */ 51 | "enable": true, 52 | "radio": 0, 53 | "if": 0 54 | }, 55 | "chan_multiSF_6": { 56 | /* Lora MAC channel, 125kHz, all SF, 867.7 MHz */ 57 | "enable": true, 58 | "radio": 0, 59 | "if": 200000 60 | }, 61 | "chan_multiSF_7": { 62 | /* Lora MAC channel, 125kHz, all SF, 867.9 MHz */ 63 | "enable": true, 64 | "radio": 0, 65 | "if": 400000 66 | }, 67 | "chan_Lora_std": { 68 | /* Lora MAC channel, 250kHz, SF7, 868.3 MHz */ 69 | "enable": true, 70 | "radio": 1, 71 | "if": -200000, 72 | "bandwidth": 250000, 73 | "spread_factor": 7 74 | }, 75 | "chan_FSK": { 76 | /* FSK 50kbps channel, 868.8 MHz */ 77 | "enable": true, 78 | "radio": 1, 79 | "if": 300000, 80 | "bandwidth": 125000, 81 | "datarate": 50000 82 | } 83 | }, 84 | "gateway_conf": { 85 | "gateway_ID": "AA555A0000000000" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /util_pkt_logger/inc/parson.h: -------------------------------------------------------------------------------- 1 | /* 2 | Parson ( http://kgabis.github.com/parson/ ) 3 | Copyright (c) 2013 Krzysztof Gabis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | #ifndef parson_parson_h 25 | #define parson_parson_h 26 | 27 | #ifdef __cplusplus 28 | extern "C" 29 | { 30 | #endif 31 | 32 | #include /* size_t */ 33 | 34 | #define PARSON_VERSION 20131130 35 | 36 | /* Types and enums */ 37 | typedef struct json_object_t JSON_Object; 38 | typedef struct json_array_t JSON_Array; 39 | typedef struct json_value_t JSON_Value; 40 | 41 | typedef enum json_value_type { 42 | JSONError = 0, 43 | JSONNull = 1, 44 | JSONString = 2, 45 | JSONNumber = 3, 46 | JSONObject = 4, 47 | JSONArray = 5, 48 | JSONBoolean = 6 49 | } JSON_Value_Type; 50 | 51 | 52 | /* Parses first JSON value in a file, returns NULL in case of error */ 53 | JSON_Value * json_parse_file(const char *filename); 54 | 55 | /* Parses first JSON value in a file and ignores comments (/ * * / and //), 56 | returns NULL in case of error */ 57 | JSON_Value * json_parse_file_with_comments(const char *filename); 58 | 59 | /* Parses first JSON value in a string, returns NULL in case of error */ 60 | JSON_Value * json_parse_string(const char *string); 61 | 62 | /* Parses first JSON value in a string and ignores comments (/ * * / and //), 63 | returns NULL in case of error */ 64 | JSON_Value * json_parse_string_with_comments(const char *string); 65 | 66 | /* JSON Object */ 67 | JSON_Value * json_object_get_value (const JSON_Object *object, const char *name); 68 | const char * json_object_get_string (const JSON_Object *object, const char *name); 69 | JSON_Object * json_object_get_object (const JSON_Object *object, const char *name); 70 | JSON_Array * json_object_get_array (const JSON_Object *object, const char *name); 71 | double json_object_get_number (const JSON_Object *object, const char *name); 72 | int json_object_get_boolean(const JSON_Object *object, const char *name); 73 | 74 | /* dotget functions enable addressing values with dot notation in nested objects, 75 | just like in structs or c++/java/c# objects (e.g. objectA.objectB.value). 76 | Because valid names in JSON can contain dots, some values may be inaccessible 77 | this way. */ 78 | JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name); 79 | const char * json_object_dotget_string (const JSON_Object *object, const char *name); 80 | JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name); 81 | JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name); 82 | double json_object_dotget_number (const JSON_Object *object, const char *name); 83 | int json_object_dotget_boolean(const JSON_Object *object, const char *name); 84 | 85 | /* Functions to get available names */ 86 | size_t json_object_get_count(const JSON_Object *object); 87 | const char * json_object_get_name (const JSON_Object *object, size_t index); 88 | 89 | /* JSON Array */ 90 | JSON_Value * json_array_get_value (const JSON_Array *array, size_t index); 91 | const char * json_array_get_string (const JSON_Array *array, size_t index); 92 | JSON_Object * json_array_get_object (const JSON_Array *array, size_t index); 93 | JSON_Array * json_array_get_array (const JSON_Array *array, size_t index); 94 | double json_array_get_number (const JSON_Array *array, size_t index); 95 | int json_array_get_boolean(const JSON_Array *array, size_t index); 96 | size_t json_array_get_count (const JSON_Array *array); 97 | 98 | /* JSON Value */ 99 | JSON_Value_Type json_value_get_type (const JSON_Value *value); 100 | JSON_Object * json_value_get_object (const JSON_Value *value); 101 | JSON_Array * json_value_get_array (const JSON_Value *value); 102 | const char * json_value_get_string (const JSON_Value *value); 103 | double json_value_get_number (const JSON_Value *value); 104 | int json_value_get_boolean(const JSON_Value *value); 105 | void json_value_free (JSON_Value *value); 106 | 107 | #ifdef __cplusplus 108 | } 109 | #endif 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /util_pkt_logger/local_conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "gateway_conf": { 3 | "gateway_ID": "AA555A0000000101" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /util_pkt_logger/readme.md: -------------------------------------------------------------------------------- 1 | / _____) _ | | 2 | ( (____ _____ ____ _| |_ _____ ____| |__ 3 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 4 | _____) ) ____| | | || |_| ____( (___| | | | 5 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 6 | (C)2013 Semtech-Cycleo 7 | 8 | LoRa packet logger 9 | =================== 10 | 11 | 1. Introduction 12 | ---------------- 13 | 14 | This software is used to set up a LoRa concentrator using a JSON configuration 15 | file and then record all the packets received in a log file, indefinitely, until 16 | the user stops the application. 17 | No filtering is done and all packets that are LoRa packets with the correct RF 18 | parameters (frequency, datarate, bandwidth) should appear in the log. 19 | 20 | 2. Dependencies 21 | ---------------- 22 | 23 | This program uses the Parson library (http://kgabis.github.com/parson/) by 24 | Krzysztof Gabis for JSON parsing. 25 | Many thanks to him for that very practical and well written library. 26 | 27 | This program is a typical example of LoRa concentrator HAL usage for receiving 28 | packets. 29 | 30 | Only high-level functions are used (the ones contained in loragw_hal) so there 31 | is no hardware dependencies assuming the HAL is matched with the proper version 32 | of the hardware. 33 | Data structures of the received packets are accessed by name (ie. not at a 34 | binary level) so new functionalities can be added to the API without affecting 35 | that program at all. 36 | 37 | It was tested with v1.3.0 of the libloragw library, and should be compatible 38 | with any later version of the library assuming the API is downward-compatible. 39 | 40 | 3. Usage 41 | --------- 42 | 43 | To stop the application, press Ctrl+C. 44 | 45 | The only optional parameter when launching the application is the log rotation 46 | time (in seconds). 47 | 48 | The way the program takes configuration files into account is the following: 49 | * if there is a debug_conf.json parse it, others are ignored 50 | * if there is a global_conf.json parse it and look for the next file 51 | * if there is a local_conf.json parse it 52 | If some parameters are defined in both global and local configuration files, the 53 | local definition overwrites the global definition. 54 | 55 | The global configuration file should be exactly the same throughout your 56 | network, contain all global parameters (parameters for "sensor" radio channels) 57 | and preferably default "safe" values for parameters that are specific for each 58 | gateway (eg. specify a default MAC address). 59 | 60 | If you have build the libloragw library for a specific radio band (eg. ETSI 61 | 868 MHz band) a ready-to-use global_conf.json file is generated by the Makefile 62 | with a set of channels typical for a 'LoRa MAC' network application. 63 | If you don't specify a radio band, an empty global_conf.json is generated and 64 | must be filled with the settings you need. 65 | 66 | The local configuration file should contain parameters that are specific to each 67 | gateway (eg. MAC address, frequency for backhaul radio channels). 68 | 69 | In each configuration file, the program looks for a JSON object named 70 | "SX1301_conf" that should contain the parameters for the LoRa concentrator board 71 | (RF channels definition, modem parameters, etc) and another JSON object called 72 | "gateway_conf" that should contain the gateway parameters (gateway MAC address, 73 | IP address of the LoRa MAC controller, network authentication parameters, etc). 74 | 75 | To learn more about the JSON configuration format, read the provided JSON files 76 | and the API documentation. A dedicated document will be available later on. 77 | 78 | The received packets are put in a CSV file whose name include the MAC address of 79 | the gateway in hexadecimal format and a UTC timestamp of log starting time in 80 | ISO 8601 recommended compact format: 81 | yyyymmddThhmmssZ (eg. 20131009T172345Z for October 9th, 2013 at 5:23:45PM UTC) 82 | 83 | To able continuous monitoring, the current log file is closed is closed and a 84 | new one is opened every hour (by default, rotation interval is settable by the 85 | user using -r command line option). 86 | No packet is lost during that rotation of log file. 87 | Every log file but the current one can then be modified, uploaded and/or deleted 88 | without any consequence for the program execution. 89 | 90 | 4. License 91 | ----------- 92 | 93 | Copyright (c) 2013, SEMTECH S.A. 94 | All rights reserved. 95 | 96 | Redistribution and use in source and binary forms, with or without 97 | modification, are permitted provided that the following conditions are met: 98 | 99 | * Redistributions of source code must retain the above copyright 100 | notice, this list of conditions and the following disclaimer. 101 | * Redistributions in binary form must reproduce the above copyright 102 | notice, this list of conditions and the following disclaimer in the 103 | documentation and/or other materials provided with the distribution. 104 | * Neither the name of the Semtech corporation nor the 105 | names of its contributors may be used to endorse or promote products 106 | derived from this software without specific prior written permission. 107 | 108 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 109 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 110 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 111 | DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY 112 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 113 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 114 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 115 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 116 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 117 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 118 | 119 | 5. License for Parson library 120 | ------------------------------ 121 | 122 | Parson ( http://kgabis.github.com/parson/ ) 123 | Copyright (c) 2012 Krzysztof Gabis 124 | 125 | Permission is hereby granted, free of charge, to any person obtaining a copy 126 | of this software and associated documentation files (the "Software"), to deal 127 | in the Software without restriction, including without limitation the rights 128 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 129 | copies of the Software, and to permit persons to whom the Software is 130 | furnished to do so, subject to the following conditions: 131 | 132 | The above copyright notice and this permission notice shall be included in 133 | all copies or substantial portions of the Software. 134 | 135 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 136 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 137 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 138 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 139 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 140 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 141 | THE SOFTWARE. 142 | 143 | *EOF* -------------------------------------------------------------------------------- /util_spectral_scan/Makefile: -------------------------------------------------------------------------------- 1 | ### Environment constants 2 | 3 | LGW_PATH ?= ../libloragw 4 | ARCH ?= 5 | CROSS_COMPILE ?= 6 | 7 | ### External constant definitions 8 | 9 | include $(LGW_PATH)/library.cfg 10 | 11 | ### Constant symbols 12 | 13 | CC = $(CROSS_COMPILE)gcc 14 | AR = $(CROSS_COMPILE)ar 15 | CFLAGS = -O2 -Wall -Wextra -std=c99 -I inc 16 | 17 | OBJDIR = obj 18 | INCLUDES = $(wildcard inc/*.h) 19 | 20 | ### Constants for LoRa concentrator HAL library 21 | # List the library sub-modules that are used by the application 22 | 23 | LGW_INC = $(LGW_PATH)/inc/config.h 24 | LGW_INC += $(LGW_PATH)/inc/loragw_hal.h 25 | 26 | ### Linking options 27 | 28 | ifeq ($(CFG_SPI),native) 29 | LIBS := -lloragw -lrt -lm 30 | else ifeq ($(CFG_SPI),ftdi) 31 | LIBS := -lloragw -lrt -lmpsse -lm 32 | else ifeq ($(CFG_SPI),mac) 33 | LIBS := -lloragw -lmpsse -lm 34 | endif 35 | 36 | ### General build targets 37 | 38 | all: util_spectral_scan 39 | 40 | clean: 41 | rm -f $(OBJDIR)/*.o 42 | rm -f util_spectral_scan 43 | 44 | ### HAL library (do no force multiple library rebuild even with 'make -B') 45 | 46 | $(LGW_PATH)/inc/config.h: 47 | @if test ! -f $@; then \ 48 | $(MAKE) all -C $(LGW_PATH); \ 49 | fi 50 | 51 | $(LGW_PATH)/libloragw.a: $(LGW_INC) 52 | @if test ! -f $@; then \ 53 | $(MAKE) all -C $(LGW_PATH); \ 54 | fi 55 | 56 | ### Sub-modules compilation 57 | 58 | $(OBJDIR): 59 | mkdir -p $(OBJDIR) 60 | 61 | $(OBJDIR)/%.o: src/%.c $(INCLUDES) | $(OBJDIR) 62 | $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@ 63 | 64 | ### Main program assembly 65 | 66 | util_spectral_scan: $(OBJDIR)/util_spectral_scan.o 67 | $(CC) -L$(LGW_PATH) $^ $(LIBS) -o $@ 68 | 69 | ### EOF 70 | -------------------------------------------------------------------------------- /util_spectral_scan/readme.md: -------------------------------------------------------------------------------- 1 | ______ _ 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2014 Semtech-Cycleo 8 | 9 | Background Spectral Scan for LoRa gateway 10 | ========================================= 11 | 12 | 13 | 1. Introduction 14 | ---------------- 15 | 16 | This software is used to scan the spectral band where the LoRa gateway operates. 17 | It simply computes a RSSI histogram on several frequencies, that will help to 18 | detect occupied bands and get interferer profiles. 19 | It logs the histogram in a .csv file. 20 | 21 | This utility program is meant to run on the LoRa gateway reference design 22 | SX1301AP2 (with FPGA and additionnal SX127x). 23 | 24 | The background RSSI scan is a diagnostic tool and must be run on top of the 25 | gateway activity. Moreover the two SX1257 radios have to be configured in RX 26 | mode to optimize the matching impedance with SX127x. The 32MHz clock provided 27 | to the SX127x is available once SX1301 has enabled the two SX1257 radios, so 28 | the background RSSI scan must be launched after the packet forwarder. 29 | 30 | 2. Command line options 31 | ------------------------ 32 | 33 | `-h` 34 | will display a short help 35 | 36 | `-f start:step:stop` 37 | Frequency vector to scan in MHz: start:step:stop 38 | Valid range: start > 800, step > 0.005, stop < 1000 39 | 40 | `-n` 41 | Total number of RSSI points. 42 | Valid range: [1,65535] 43 | 44 | `-r` 45 | Divide factor of RSSI sampling rate, which is 32MHz/(div+1030) 46 | Valid range: [1,65535] 47 | 48 | `-l` 49 | Log file name 50 | 51 | 52 | 3. Use 53 | ------- 54 | 55 | The format of the log file is the following: 56 | Freq_1, RSSI_1, histo_1, ...., RSSI_128, histo_128 57 | Freq_2, RSSI_1, histo_1, ...., RSSI_128, histo_128 58 | ... 59 | 60 | RSSI_n is the nth value of RSSI in dBm, starting at -142 dBm 61 | 62 | Default setup: 63 | - freq 863 : 0.2 : 870 64 | - 65535 RSSI points in total at 32kHz rate 65 | - FTDI SPI interface 66 | 67 | Example with frequencies from 865 MHz to 870 MHz, by step of 1MHz, 68 | 2500 RSSI points processed at 10kHz rate, saved in "log.csv": 69 | ./util_spectral_scan -f 865:1:870 -n 2500 -r 20170 -l "log" 70 | -------------------------------------------------------------------------------- /util_spectral_scan/src/util_spectral_scan.c: -------------------------------------------------------------------------------- 1 | /* 2 | ______ _ 3 | / _____) _ | | 4 | ( (____ _____ ____ _| |_ _____ ____| |__ 5 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 6 | _____) ) ____| | | || |_| ____( (___| | | | 7 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 8 | (C)2014 Semtech-Cycleo 9 | 10 | Description: 11 | SX1301 spectral scan 12 | 13 | License: Revised BSD License, see LICENSE.TXT file include in the project 14 | Maintainer: Matthieu Leurent 15 | */ 16 | 17 | 18 | /* -------------------------------------------------------------------------- */ 19 | /* --- DEPENDENCIES --------------------------------------------------------- */ 20 | 21 | /* Fix an issue between POSIX and C99 */ 22 | #ifdef __MACH__ 23 | #elif __STDC_VERSION__ >= 199901L 24 | #define _XOPEN_SOURCE 600 25 | #else 26 | #define _XOPEN_SOURCE 500 27 | #endif 28 | 29 | #include /* C99 types */ 30 | #include /* NULL printf */ 31 | #include /* EXIT atoi */ 32 | #include /* getopt */ 33 | #include 34 | 35 | #include "loragw_aux.h" 36 | #include "loragw_reg.h" 37 | #include "loragw_hal.h" 38 | #include "loragw_radio.h" 39 | #include "loragw_fpga.h" 40 | 41 | /* -------------------------------------------------------------------------- */ 42 | /* --- MACROS & CONSTANTS --------------------------------------------------- */ 43 | 44 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 45 | 46 | #define DEFAULT_START_FREQ 863000000 /* start frequency, Hz */ 47 | #define DEFAULT_STOP_FREQ 870000000 /* stop frequency, Hz */ 48 | #define DEFAULT_STEP_FREQ 200000 /* frequency step, Hz */ 49 | #define DEFAULT_RSSI_PTS 65535 /* number of RSSI reads */ 50 | #define DEFAULT_RSSI_RATE_DIV 1 /* RSSI sampling rate = 32MHz/(div+1030)*/ 51 | #define DEFAULT_LOG_NAME "rssi_histogram" 52 | 53 | #define RSSI_RANGE 256 54 | #define RSSI_OFFSET -135 55 | 56 | #define MAX_FREQ 1000000000 57 | #define MIN_FREQ 800000000 58 | #define MIN_STEP_FREQ 5000 59 | 60 | /* -------------------------------------------------------------------------- */ 61 | /* --- GLOBAL VARIABLES ----------------------------------------------------- */ 62 | 63 | /* -------------------------------------------------------------------------- */ 64 | /* --- MAIN FUNCTION -------------------------------------------------------- */ 65 | 66 | int main( int argc, char ** argv ) 67 | { 68 | int i, j, k; /* loop and temporary variables */ 69 | int x; /* return code for functions */ 70 | int32_t reg_val; 71 | 72 | /* Parameter parsing */ 73 | double arg_lf[3] = {0,0,0}; 74 | unsigned arg_u = 0; 75 | char arg_s[64]; 76 | 77 | /* Application parameters */ 78 | uint32_t start_freq = DEFAULT_START_FREQ; 79 | uint32_t stop_freq = DEFAULT_STOP_FREQ; 80 | uint32_t step_freq = DEFAULT_STEP_FREQ; 81 | uint16_t rssi_pts = DEFAULT_RSSI_PTS; 82 | uint16_t rssi_rate_div = DEFAULT_RSSI_RATE_DIV; 83 | char log_file_name[64] = DEFAULT_LOG_NAME; 84 | FILE * log_file = NULL; 85 | 86 | /* Local var */ 87 | int freq_nb; 88 | uint32_t freq; 89 | uint8_t read_burst[RSSI_RANGE*2]; 90 | uint16_t rssi_histo; 91 | uint16_t rssi_cumu; 92 | float rssi_thresh[] = {0.1,0.3,0.5,0.8,1}; 93 | 94 | /* Parse command line options */ 95 | while( (i = getopt( argc, argv, "hud::f:n:r:l:" )) != -1 ) 96 | { 97 | switch( i ) 98 | { 99 | case 'h': 100 | printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" ); 101 | printf( " -f :: Frequency vector to scan in MHz (start:step:stop)\n" ); 102 | printf( " start>%3.3f step>%1.3f stop<%3.3f\n", MIN_FREQ/1e6, MIN_STEP_FREQ/1e6, MAX_FREQ/1e6 ); 103 | printf( " -n Total number of RSSI points, [1,65535]\n" ); 104 | printf( " -r Divide factor of RSSI sampling rate, 32MHz/(div+1030), [1,65535]\n" ); 105 | printf( " -l Log file name\n" ); 106 | printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" ); 107 | return EXIT_SUCCESS; 108 | break; 109 | 110 | case 'f': /* -f :: Frequency vector to scan in MHz, start:step:stop */ 111 | j = sscanf( optarg, "%lf:%lf:%lf", &arg_lf[0], &arg_lf[1], &arg_lf[2] ); 112 | if( (j!=3) || (arg_lf[0] < MIN_FREQ/1e6) || (arg_lf[0] > MAX_FREQ/1e6) || (arg_lf[1] < MIN_STEP_FREQ/1e6) || (arg_lf[2] < MIN_FREQ/1e6) || (arg_lf[2] > MAX_FREQ/1e6) ) 113 | { 114 | printf( "ERROR: argument parsing of -f argument. -h for help.\n" ); 115 | return EXIT_FAILURE; 116 | } 117 | else 118 | { 119 | start_freq = (uint32_t)((arg_lf[0] * 1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ 120 | step_freq = (uint32_t)((arg_lf[1] * 1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ 121 | stop_freq = (uint32_t)((arg_lf[2] * 1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ 122 | } 123 | break; 124 | 125 | case 'n': /* -n Total number of RSSI points, [1,65535] */ 126 | j = sscanf( optarg, "%i", &arg_u ); 127 | if( (j != 1) || (arg_u < 1) || (arg_u > 65535) ) 128 | { 129 | printf( "ERROR: argument parsing of -n argument. -h for help.\n" ); 130 | return EXIT_FAILURE; 131 | } 132 | else 133 | { 134 | rssi_pts = (uint16_t)arg_u; 135 | } 136 | break; 137 | 138 | case 'r': /* -r Divide factor of RSSI sampling rate, 32MHz/(div+1030), [1,65535] */ 139 | j = sscanf( optarg, "%i", &arg_u ); 140 | if( (j != 1) || (arg_u < 1) || (arg_u > 65535) ) 141 | { 142 | printf( "ERROR: argument parsing of -r argument. -h for help.\n" ); 143 | return EXIT_FAILURE; 144 | } 145 | else 146 | { 147 | rssi_rate_div = (uint16_t)arg_u; 148 | } 149 | break; 150 | 151 | case 'l': /* -l Log file name */ 152 | j = sscanf( optarg, "%s", arg_s ); 153 | if( j != 1 ) 154 | { 155 | printf( "ERROR: argument parsing of -l argument. -h for help.\n" ); 156 | return EXIT_FAILURE; 157 | } 158 | else 159 | { 160 | sprintf(log_file_name, "%s", arg_s); 161 | } 162 | break; 163 | 164 | default: 165 | printf( "ERROR: argument parsing options. -h for help.\n" ); 166 | return EXIT_FAILURE; 167 | } 168 | } 169 | 170 | /* Start message */ 171 | printf( "+++ Start spectral scan of LoRa gateway channels +++\n" ); 172 | 173 | x = lgw_connect( ); 174 | if( x != 0 ) 175 | { 176 | printf( "ERROR: Failed to connect to FPGA\n" ); 177 | return EXIT_FAILURE; 178 | } 179 | 180 | /* Check if FPGA supports Spectral Scan */ 181 | lgw_fpga_reg_r(LGW_FPGA_FPGA_FEATURE, ®_val); 182 | if (TAKE_N_BITS_FROM((uint8_t)reg_val, 1, 1) != true) { 183 | printf("ERROR: Spectral Scan is not supported (0x%x)\n", (uint8_t)reg_val); 184 | return EXIT_FAILURE; 185 | } 186 | 187 | /* Configure FPGA */ 188 | x = lgw_fpga_reg_w(LGW_FPGA_HISTO_TEMPO, rssi_rate_div); 189 | x |= lgw_fpga_reg_w(LGW_FPGA_HISTO_NB_READ, rssi_pts); 190 | if( x != LGW_REG_SUCCESS ) 191 | { 192 | printf( "ERROR: Failed to configure FPGA\n" ); 193 | return EXIT_FAILURE; 194 | } 195 | 196 | /* create log file */ 197 | strcat(log_file_name,".csv"); 198 | log_file = fopen(log_file_name, "w"); 199 | if (log_file == NULL) 200 | { 201 | printf( "ERROR: impossible to create log file %s\n", log_file_name ); 202 | return EXIT_FAILURE; 203 | } 204 | printf( "Writing to file: %s\n", log_file_name ); 205 | 206 | /* Number of frequency steps */ 207 | freq_nb = (int)( (stop_freq - start_freq) / step_freq ) + 1; 208 | printf( "Scanning frequencies:\nstart: %d Hz\nstop : %d Hz\nstep : %d Hz\nnb : %d\n", start_freq, stop_freq, step_freq, freq_nb ); 209 | 210 | /* Main loop */ 211 | for( j = 0; j < freq_nb; j++ ) 212 | { 213 | /* Current frequency */ 214 | freq = start_freq + j * step_freq; 215 | printf( "%d", freq ); 216 | 217 | /* Set SX127x */ 218 | x = lgw_setup_sx127x( freq, MOD_LORA ); 219 | if( x != 0 ) 220 | { 221 | printf( "ERROR: SX127x setup failed\n" ); 222 | return EXIT_FAILURE; 223 | } 224 | 225 | /* Start histogram */ 226 | lgw_fpga_reg_w(LGW_FPGA_CTRL_FEATURE_START, 1); 227 | 228 | /* Wait until rssi_pts have been processed */ 229 | do 230 | { 231 | wait_ms(1000); 232 | lgw_fpga_reg_r(LGW_FPGA_FPGA_STATUS, ®_val); 233 | } 234 | while( (reg_val & 0x0F) != 8 ); 235 | 236 | /* Stop histogram */ 237 | lgw_fpga_reg_w(LGW_FPGA_CTRL_FEATURE_START, 0); 238 | 239 | /* Read histogram */ 240 | lgw_fpga_reg_w(LGW_FPGA_HISTO_RAM_ADDR, 0); 241 | lgw_fpga_reg_rb(LGW_FPGA_HISTO_RAM_DATA, read_burst, RSSI_RANGE*2); 242 | 243 | fprintf( log_file, "%d", freq ); 244 | rssi_cumu = 0; 245 | k = 0; 246 | for( i = 0; i < RSSI_RANGE; i++ ) 247 | { 248 | rssi_histo = (uint16_t)read_burst[2*i] | ((uint16_t)read_burst[2*i+1] << 8); 249 | fprintf(log_file, ",%d,%d", i+RSSI_OFFSET, rssi_histo); 250 | rssi_cumu += rssi_histo; 251 | if( rssi_cumu > rssi_thresh[k]*rssi_pts ) 252 | { 253 | printf( " %d%%<%4d", (uint16_t)(rssi_thresh[k]*100), i+RSSI_OFFSET ); 254 | k++; 255 | } 256 | } 257 | fprintf( log_file, "\n" ); 258 | printf( "\n" ); 259 | } 260 | fclose( log_file ); 261 | 262 | /* Close SPI */ 263 | x = lgw_disconnect( ); 264 | if( x != 0 ) 265 | { 266 | printf( "ERROR: Failed to disconnect FPGA\n" ); 267 | return EXIT_FAILURE; 268 | } 269 | 270 | printf( "+++ Exiting Spectral scan program +++\n" ); 271 | 272 | return EXIT_SUCCESS; 273 | } 274 | 275 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 276 | 277 | /* --- EOF ------------------------------------------------------------------ */ 278 | 279 | -------------------------------------------------------------------------------- /util_spi_stress/Makefile: -------------------------------------------------------------------------------- 1 | ### Application-specific constants 2 | 3 | APP_NAME := util_spi_stress 4 | 5 | ### Environment constants 6 | 7 | LGW_PATH ?= ../libloragw 8 | ARCH ?= 9 | CROSS_COMPILE ?= 10 | 11 | ### External constant definitions 12 | # must get library build option to know if mpsse must be linked or not 13 | 14 | include $(LGW_PATH)/library.cfg 15 | 16 | ### Constant symbols 17 | 18 | CC := $(CROSS_COMPILE)gcc 19 | AR := $(CROSS_COMPILE)ar 20 | 21 | CFLAGS=-O2 -Wall -Wextra -std=c99 -Iinc -I. 22 | 23 | OBJDIR = obj 24 | 25 | ### Constants for LoRa concentrator HAL library 26 | # List the library sub-modules that are used by the application 27 | 28 | LGW_INC = $(LGW_PATH)/inc/config.h 29 | LGW_INC += $(LGW_PATH)/inc/loragw_reg.h 30 | 31 | ### Linking options 32 | 33 | ifeq ($(CFG_SPI),native) 34 | LIBS := -lloragw -lrt -lm 35 | else ifeq ($(CFG_SPI),ftdi) 36 | LIBS := -lloragw -lrt -lmpsse -lm 37 | else ifeq ($(CFG_SPI),mac) 38 | LIBS := -lloragw -lmpsse -lm 39 | endif 40 | 41 | ### General build targets 42 | 43 | all: $(APP_NAME) 44 | 45 | clean: 46 | rm -f $(OBJDIR)/*.o 47 | rm -f $(APP_NAME) 48 | 49 | ### HAL library (do no force multiple library rebuild even with 'make -B') 50 | 51 | $(LGW_PATH)/inc/config.h: 52 | @if test ! -f $@; then \ 53 | $(MAKE) all -C $(LGW_PATH); \ 54 | fi 55 | 56 | $(LGW_PATH)/libloragw.a: $(LGW_INC) 57 | @if test ! -f $@; then \ 58 | $(MAKE) all -C $(LGW_PATH); \ 59 | fi 60 | 61 | ### Main program compilation and assembly 62 | 63 | $(OBJDIR): 64 | mkdir -p $(OBJDIR) 65 | 66 | $(OBJDIR)/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) | $(OBJDIR) 67 | $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@ 68 | 69 | $(APP_NAME): $(OBJDIR)/$(APP_NAME).o $(LGW_PATH)/libloragw.a 70 | $(CC) -L$(LGW_PATH) $< -o $@ $(LIBS) 71 | 72 | ### EOF 73 | -------------------------------------------------------------------------------- /util_spi_stress/readme.md: -------------------------------------------------------------------------------- 1 | / _____) _ | | 2 | ( (____ _____ ____ _| |_ _____ ____| |__ 3 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 4 | _____) ) ____| | | || |_| ____( (___| | | | 5 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 6 | (C)2013 Semtech-Cycleo 7 | 8 | LoRa concentrator SPI stress test 9 | ================================== 10 | 11 | 1. Introduction 12 | ---------------- 13 | 14 | This software is used to check the reliability of the link between the host 15 | platform (on which the program is run) and the LoRa concentrator register file 16 | that is the interface through which all interaction with the LoRa concentrator 17 | happens. 18 | 19 | 2. Dependencies 20 | ---------------- 21 | 22 | This program only access the LoRa concentrator HAL library through its 23 | loragw_reg "named registers" access sub-module. 24 | 25 | It was tested with v1.3.0 of the libloragw library, and should be compatible 26 | with any later version of the library and the hardware, assuming the registers 27 | used for the tests are still present. 28 | 29 | The registers used are: 30 | * LGW_VERSION 31 | * LGW_IMPLICIT_PAYLOAD_LENGHT 32 | * LGW_FSK_REF_PATTERN_LSB 33 | * LGW_RX_DATA_BUF_ADDR 34 | * LGW_RX_DATA_BUF_DATA 35 | 36 | A data buffer accessible through the 2 registers above must be implemented. 37 | 38 | 3. Usage 39 | --------- 40 | 41 | The tests run forever or until an error is detected. 42 | Press Ctrl+C to stop the application. 43 | 44 | When an error is detected, diagnosis information are displayed. Please refer to 45 | the source code for more details on what is displayed for diagnosis. 46 | 47 | All tests use pseudo-random data generated by the rand() function. The random 48 | generator is not seeded, and the same sequence of data will be use each time the 49 | program is launched. 50 | 51 | Basically, some random data is written, read back and then compared to the 52 | initial written data. Some "useless" read on others registers might be inserted 53 | to be sure that the data read back is coming from the hardware, and not from the 54 | internal buffer(s) of the software driver(s). 55 | 56 | Test 1 > R/W on a simple 8-bit register 57 | 58 | Test 2 > R/W on a simple 8-bit register with interstitial reads on VERSION 59 | 60 | Test 3 > R/W on a 32-bit register (short SPI bursts access) 61 | 62 | Test 4 > data buffer R/W (long SPI bursts access) 63 | 64 | 4. License 65 | ----------- 66 | 67 | Copyright (c) 2013, SEMTECH S.A. 68 | All rights reserved. 69 | 70 | Redistribution and use in source and binary forms, with or without 71 | modification, are permitted provided that the following conditions are met: 72 | 73 | * Redistributions of source code must retain the above copyright 74 | notice, this list of conditions and the following disclaimer. 75 | * Redistributions in binary form must reproduce the above copyright 76 | notice, this list of conditions and the following disclaimer in the 77 | documentation and/or other materials provided with the distribution. 78 | * Neither the name of the Semtech corporation nor the 79 | names of its contributors may be used to endorse or promote products 80 | derived from this software without specific prior written permission. 81 | 82 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 83 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 84 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 85 | DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY 86 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 87 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 88 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 89 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 90 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 91 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 92 | 93 | *EOF* -------------------------------------------------------------------------------- /util_spi_stress/src/util_spi_stress.c: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | SPI stress test 11 | 12 | License: Revised BSD License, see LICENSE.TXT file include in the project 13 | Maintainer: Sylvain Miermont 14 | */ 15 | 16 | 17 | /* -------------------------------------------------------------------------- */ 18 | /* --- DEPENDANCIES --------------------------------------------------------- */ 19 | 20 | /* fix an issue between POSIX and C99 */ 21 | #ifdef __MACH__ 22 | #elif __STDC_VERSION__ >= 199901L 23 | #define _XOPEN_SOURCE 600 24 | #else 25 | #define _XOPEN_SOURCE 500 26 | #endif 27 | 28 | #include /* C99 types */ 29 | #include /* bool type */ 30 | #include /* printf fprintf sprintf fopen fputs */ 31 | 32 | #include /* sigaction */ 33 | #include /* getopt access */ 34 | #include /* rand */ 35 | 36 | #include "loragw_reg.h" 37 | 38 | /* -------------------------------------------------------------------------- */ 39 | /* --- PRIVATE MACROS ------------------------------------------------------- */ 40 | 41 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 42 | #define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */ 43 | 44 | /* -------------------------------------------------------------------------- */ 45 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ 46 | 47 | #define VERS 103 48 | #define READS_WHEN_ERROR 16 /* number of times a read is repeated if there is a read error */ 49 | #define BUFF_SIZE 1024 /* maximum number of bytes that we can write in sx1301 RX data buffer */ 50 | 51 | /* -------------------------------------------------------------------------- */ 52 | /* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ 53 | 54 | /* signal handling variables */ 55 | struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ 56 | static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ 57 | static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */ 58 | 59 | /* -------------------------------------------------------------------------- */ 60 | /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ 61 | 62 | static void sig_handler(int sigio); 63 | 64 | void usage (void); 65 | 66 | /* -------------------------------------------------------------------------- */ 67 | /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ 68 | 69 | static void sig_handler(int sigio) { 70 | if (sigio == SIGQUIT) { 71 | quit_sig = 1;; 72 | } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { 73 | exit_sig = 1; 74 | } 75 | } 76 | 77 | /* describe command line options */ 78 | void usage(void) { 79 | MSG( "Available options:\n"); 80 | MSG( " -h print this help\n"); 81 | MSG( " -t specify which test you want to run (1-4)\n"); 82 | } 83 | 84 | /* -------------------------------------------------------------------------- */ 85 | /* --- MAIN FUNCTION -------------------------------------------------------- */ 86 | 87 | int main(int argc, char **argv) 88 | { 89 | int i; 90 | int xi = 0; 91 | 92 | /* application option */ 93 | int test_number = 1; 94 | int cycle_number = 0; 95 | int repeats_per_cycle = 1000; 96 | bool error = false; 97 | 98 | /* in/out variables */ 99 | int32_t test_value; 100 | int32_t read_value; 101 | int32_t rb1, rb2, rb3; /* interstitial readbacks, to flush buffers if needed */ 102 | 103 | /* data buffer */ 104 | int32_t test_addr; 105 | uint8_t test_buff[BUFF_SIZE]; 106 | uint8_t read_buff[BUFF_SIZE]; 107 | 108 | /* parse command line options */ 109 | while ((i = getopt (argc, argv, "ht:")) != -1) { 110 | switch (i) { 111 | case 'h': 112 | usage(); 113 | return EXIT_FAILURE; 114 | break; 115 | 116 | case 't': 117 | i = sscanf(optarg, "%i", &xi); 118 | if ((i != 1) || (xi < 1) || (xi > 4)) { 119 | MSG("ERROR: invalid test number\n"); 120 | return EXIT_FAILURE; 121 | } else { 122 | test_number = xi; 123 | } 124 | break; 125 | 126 | default: 127 | MSG("ERROR: argument parsing use -h option for help\n"); 128 | usage(); 129 | return EXIT_FAILURE; 130 | } 131 | } 132 | MSG("INFO: Starting LoRa concentrator SPI stress-test number %i\n", test_number); 133 | 134 | /* configure signal handling */ 135 | sigemptyset(&sigact.sa_mask); 136 | sigact.sa_flags = 0; 137 | sigact.sa_handler = sig_handler; 138 | sigaction(SIGQUIT, &sigact, NULL); 139 | sigaction(SIGINT, &sigact, NULL); 140 | sigaction(SIGTERM, &sigact, NULL); 141 | 142 | /* start SPI link */ 143 | i = lgw_connect(); 144 | if (i != LGW_REG_SUCCESS) { 145 | MSG("ERROR: lgw_connect() did not return SUCCESS"); 146 | return EXIT_FAILURE; 147 | } 148 | 149 | if (test_number == 1) { 150 | /* single 8b register R/W stress test */ 151 | while ((quit_sig != 1) && (exit_sig != 1)) { 152 | printf("Cycle %i > ", cycle_number); 153 | for (i=0; i ", cycle_number); 180 | for (i=0; i ", cycle_number); 210 | for (i=0; i ", cycle_number); 241 | test_addr = rand() & 0xFFFF; 242 | lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* write at random offset in memory */ 243 | lgw_reg_wb(LGW_RX_DATA_BUF_DATA, test_buff, BUFF_SIZE); 244 | lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* go back to start of segment */ 245 | lgw_reg_rb(LGW_RX_DATA_BUF_DATA, read_buff, BUFF_SIZE); 246 | for (i=0; ((i