├── .gitignore ├── IMG_3002 (1).JPG ├── IMG_3002.JPG ├── LICENSE ├── Makefile ├── VERSION ├── iot868stk.png ├── libloragw ├── 99-libftdi.rules ├── Makefile ├── inc │ ├── loragw_aux.h │ ├── loragw_gps.h │ ├── loragw_hal.h │ ├── loragw_reg.h │ └── loragw_spi.h ├── install_ftdi.txt ├── library.cfg ├── obj │ └── .gitkeep ├── readme.md ├── src │ ├── agc_fw.var │ ├── arb_fw.var │ ├── cal_fw.var │ ├── loragw_aux.c │ ├── loragw_gps.c │ ├── loragw_hal.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 ├── lora_card.jpg ├── mcard1.bmp.jpg ├── readme.md ├── util_pkt_logger ├── Makefile ├── global_conf.json ├── inc │ └── parson.h ├── local_conf.json ├── obj │ └── .gitkeep ├── readme.md └── src │ ├── parson.c │ └── util_pkt_logger.c ├── util_spi_stress ├── Makefile ├── obj │ └── .gitkeep ├── readme.md └── src │ └── util_spi_stress.c ├── util_tx_continuous ├── Makefile ├── obj │ └── .gitkeep ├── readme.md └── src │ ├── cal_tx_fw.var │ ├── util_fw.var │ └── util_tx_continuous.c └── util_tx_test ├── Makefile ├── obj └── .gitkeep ├── readme.md └── src └── util_tx_test.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.swp 3 | *.bak 4 | -------------------------------------------------------------------------------- /IMG_3002 (1).JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirakonta/lora_gateway/0642acb11d56150f619d76f809fdfa48280df80e/IMG_3002 (1).JPG -------------------------------------------------------------------------------- /IMG_3002.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirakonta/lora_gateway/0642acb11d56150f619d76f809fdfa48280df80e/IMG_3002.JPG -------------------------------------------------------------------------------- /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_tx_test 14 | $(MAKE) all -e -C util_tx_continuous 15 | 16 | clean: 17 | $(MAKE) clean -e -C libloragw 18 | $(MAKE) clean -e -C util_pkt_logger 19 | $(MAKE) clean -e -C util_spi_stress 20 | $(MAKE) clean -e -C util_tx_test 21 | $(MAKE) clean -e -C util_tx_continuous 22 | 23 | ### EOF 24 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 3.1.0 2 | -------------------------------------------------------------------------------- /iot868stk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirakonta/lora_gateway/0642acb11d56150f619d76f809fdfa48280df80e/iot868stk.png -------------------------------------------------------------------------------- /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 | 10 | # FTDI Devices: FT2232H 11 | SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="0664", GROUP="plugdev" 12 | -------------------------------------------------------------------------------- /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 | CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I. 14 | 15 | ### library.cfg configuration file processing 16 | 17 | ifeq ($(CFG_SPI),native) 18 | CFG_SPI_MSG := Linux native SPI driver 19 | CFG_SPI_OPT := CFG_SPI_NATIVE 20 | else ifeq ($(CFG_SPI),ftdi) 21 | CFG_SPI_MSG := FTDI SPI-over-USB bridge using libmpsse/libftdi/libusb 22 | CFG_SPI_OPT := CFG_SPI_FTDI 23 | else 24 | $(error No SPI physical layer selected, check ../target.cfg file.) 25 | endif 26 | 27 | ### linking options 28 | 29 | ifeq ($(CFG_SPI),native) 30 | LIBS := -lloragw -lrt -lm 31 | else ifeq ($(CFG_SPI),ftdi) 32 | LIBS := -lloragw -lrt -lmpsse -lm 33 | endif 34 | 35 | ### general build targets 36 | 37 | all: libloragw.a test_loragw_spi test_loragw_reg test_loragw_hal test_loragw_gps test_loragw_cal 38 | 39 | clean: 40 | rm -f libloragw.a 41 | rm -f test_loragw_* 42 | rm -f obj/*.o 43 | rm -f inc/config.h 44 | 45 | ### transpose library.cfg into a C header file : config.h 46 | 47 | inc/config.h: ../VERSION library.cfg 48 | @echo "*** Checking libloragw library configuration ***" 49 | @rm -f $@ 50 | # File initialization 51 | @echo "#ifndef _LORAGW_CONFIGURATION_H" >> $@ 52 | @echo "#define _LORAGW_CONFIGURATION_H" >> $@ 53 | # Release version 54 | @echo "Release version : $(LIBLORAGW_VERSION)" 55 | @echo " #define LIBLORAGW_VERSION "\"$(LIBLORAGW_VERSION)\""" >> $@ 56 | # SPI interface 57 | @echo "SPI interface : $(CFG_SPI_MSG)" 58 | @echo " #define $(CFG_SPI_OPT) 1" >> $@ 59 | # Debug options 60 | @echo " #define DEBUG_AUX $(DEBUG_AUX)" >> $@ 61 | @echo " #define DEBUG_SPI $(DEBUG_SPI)" >> $@ 62 | @echo " #define DEBUG_REG $(DEBUG_REG)" >> $@ 63 | @echo " #define DEBUG_HAL $(DEBUG_HAL)" >> $@ 64 | @echo " #define DEBUG_GPS $(DEBUG_GPS)" >> $@ 65 | @echo " #define DEBUG_GPIO $(DEBUG_GPIO)" >> $@ 66 | # end of file 67 | @echo "#endif" >> $@ 68 | @echo "*** Configuration seems ok ***" 69 | 70 | ### library module target 71 | 72 | obj/loragw_aux.o: src/loragw_aux.c inc/loragw_aux.h inc/config.h 73 | $(CC) -c $(CFLAGS) $< -o $@ 74 | 75 | ifeq ($(CFG_SPI),native) 76 | obj/loragw_spi.o: src/loragw_spi.native.c inc/loragw_spi.h inc/config.h 77 | $(CC) -c $(CFLAGS) $< -o $@ 78 | else ifeq ($(CFG_SPI),ftdi) 79 | obj/loragw_spi.o: src/loragw_spi.ftdi.c inc/loragw_spi.h inc/config.h 80 | $(CC) -c $(CFLAGS) $< -o $@ 81 | endif 82 | 83 | obj/loragw_reg.o: src/loragw_reg.c inc/loragw_reg.h inc/loragw_spi.h inc/config.h 84 | $(CC) -c $(CFLAGS) $< -o $@ 85 | 86 | obj/loragw_hal.o: src/loragw_hal.c inc/loragw_hal.h inc/loragw_reg.h inc/loragw_aux.h src/arb_fw.var src/agc_fw.var src/cal_fw.var inc/config.h 87 | $(CC) -c $(CFLAGS) $< -o $@ 88 | 89 | obj/loragw_gps.o: src/loragw_gps.c inc/loragw_gps.h inc/config.h 90 | $(CC) -c $(CFLAGS) $< -o $@ 91 | 92 | ### static library 93 | 94 | ifeq ($(CFG_SPI),native) 95 | libloragw.a: obj/loragw_hal.o obj/loragw_gps.o obj/loragw_reg.o obj/loragw_spi.o obj/loragw_aux.o 96 | else ifeq ($(CFG_SPI),ftdi) 97 | libloragw.a: obj/loragw_hal.o obj/loragw_gps.o obj/loragw_reg.o obj/loragw_spi.o obj/loragw_aux.o 98 | endif 99 | $(AR) rcs $@ $^ 100 | 101 | ### test programs 102 | 103 | test_loragw_spi: tst/test_loragw_spi.c libloragw.a 104 | $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS) 105 | 106 | test_loragw_reg: tst/test_loragw_reg.c libloragw.a 107 | $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS) 108 | 109 | test_loragw_hal: tst/test_loragw_hal.c libloragw.a 110 | $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS) 111 | 112 | test_loragw_gps: tst/test_loragw_gps.c libloragw.a 113 | $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS) 114 | 115 | test_loragw_cal: tst/test_loragw_cal.c libloragw.a src/cal_fw.var 116 | $(CC) $(CFLAGS) -L. $< -o $@ $(LIBS) 117 | 118 | ### EOF 119 | -------------------------------------------------------------------------------- /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 FUNCTIONS PROTOTYPES ------------------------------------------ */ 27 | 28 | /** 29 | @brief Wait for a certain time (millisecond accuracy) 30 | @param t number of milliseconds to wait. 31 | */ 32 | void wait_ms(unsigned long t); 33 | 34 | #endif 35 | 36 | /* --- EOF ------------------------------------------------------------------ */ 37 | -------------------------------------------------------------------------------- /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 | #if __STDC_VERSION__ >= 199901L 27 | #define _XOPEN_SOURCE 600 28 | #else 29 | #define _XOPEN_SOURCE 500 30 | #endif 31 | 32 | #include /* C99 types */ 33 | #include /* time library */ 34 | #include /* speed_t */ 35 | 36 | #include "config.h" /* library configuration options (dynamically generated) */ 37 | 38 | /* -------------------------------------------------------------------------- */ 39 | /* --- PUBLIC TYPES --------------------------------------------------------- */ 40 | 41 | /** 42 | @struct coord_s 43 | @brief Time solution required for timestamp to absolute time conversion 44 | */ 45 | struct tref { 46 | time_t systime; /*!> system time when solution was calculated */ 47 | uint32_t count_us; /*!> reference concentrator internal timestamp */ 48 | struct timespec utc; /*!> reference UTC time (from GPS) */ 49 | double xtal_err; /*!> raw clock error (eg. <1 'slow' XTAL) */ 50 | }; 51 | 52 | /** 53 | @struct coord_s 54 | @brief Geodesic coordinates 55 | */ 56 | struct coord_s { 57 | double lat; /*!> latitude [-90,90] (North +, South -) */ 58 | double lon; /*!> longitude [-180,180] (East +, West -)*/ 59 | short alt; /*!> altitude in meters (WGS 84 geoid ref.) */ 60 | }; 61 | 62 | /** 63 | @enum gps_msg 64 | @brief Type of GPS (and other GNSS) sentences 65 | */ 66 | enum gps_msg { 67 | UNKNOWN, /*!> neutral value */ 68 | IGNORED, /*!> frame was not parsed by the system */ 69 | INVALID, /*!> system try to parse frame but failed */ 70 | /* NMEA messages of interest */ 71 | NMEA_RMC, /*!> Recommended Minimum data (time + date) */ 72 | NMEA_GGA, /*!> Global positioning system fix data (pos + alt) */ 73 | NMEA_GNS, /*!> GNSS fix data (pos + alt, sat number) */ 74 | NMEA_ZDA, /*!> Time and Date */ 75 | /* NMEA message useful for time reference quality assessment */ 76 | NMEA_GBS, /*!> GNSS Satellite Fault Detection */ 77 | NMEA_GST, /*!> GNSS Pseudo Range Error Statistics */ 78 | NMEA_GSA, /*!> GNSS DOP and Active Satellites (sat number) */ 79 | NMEA_GSV, /*!> GNSS Satellites in View (sat SNR) */ 80 | /* Misc. NMEA messages */ 81 | NMEA_GLL, /*!> Latitude and longitude, with time fix and status */ 82 | NMEA_TXT, /*!> Text Transmission */ 83 | NMEA_VTG, /*!> Course over ground and Ground speed */ 84 | /* uBlox proprietary NMEA messages of interest */ 85 | UBX_POSITION, /*!> */ 86 | UBX_TIME /*!> */ 87 | }; 88 | 89 | /* -------------------------------------------------------------------------- */ 90 | /* --- PUBLIC CONSTANTS ----------------------------------------------------- */ 91 | 92 | #define LGW_GPS_SUCCESS 0 93 | #define LGW_GPS_ERROR -1 94 | 95 | /* -------------------------------------------------------------------------- */ 96 | /* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */ 97 | 98 | /** 99 | @brief Configure a GPS module 100 | 101 | @param tty_path path to the TTY connected to the GPS 102 | @param gps_familly parameter (eg. ubx6 for uBlox gen.6) 103 | @param target_brate target baudrate for communication (0 keeps default target baudrate) 104 | @param fd_ptr pointer to a variable to receive file descriptor on GPS tty 105 | @return success if the function was able to connect and configure a GPS module 106 | */ 107 | int lgw_gps_enable(char* tty_path, char* gps_familly, speed_t target_brate, int* fd_ptr); 108 | 109 | /** 110 | @brief Parse messages coming from the GPS system (or other GNSS) 111 | 112 | @param serial_buff pointer to the string to be parsed 113 | @param buff_size maximum string lengths for NMEA parsing (incl. null char) 114 | @return type of frame parsed 115 | 116 | The RAW NMEA sentences are parsed to a global set of variables shared with the 117 | lgw_gps_get function. 118 | If the lgw_parse_nmea and lgw_gps_get are used in different threads, a mutex 119 | lock must be acquired before calling either function. 120 | */ 121 | enum gps_msg lgw_parse_nmea(char* serial_buff, int buff_size); 122 | 123 | /** 124 | @brief Get the GPS solution (space & time) for the concentrator 125 | 126 | @param utc pointer to store UTC time, with ns precision (NULL to ignore) 127 | @param loc pointer to store coordinates (NULL to ignore) 128 | @param err pointer to store coordinates standard deviation (NULL to ignore) 129 | @return success if the chosen elements could be returned 130 | 131 | This function read the global variables generated by the NMEA parsing function 132 | lgw_parse_nmea. It returns time and location data in a format that is 133 | exploitable by other functions in that library sub-module. 134 | If the lgw_parse_nmea and lgw_gps_get are used in different threads, a mutex 135 | lock must be acquired before calling either function. 136 | */ 137 | int lgw_gps_get(struct timespec* utc, struct coord_s* loc, struct coord_s* err); 138 | 139 | /** 140 | @brief Take a timestamp and UTC time and refresh reference for time conversion 141 | 142 | @param ref pointer to time reference structure 143 | @param old_ref previous time reference (NULL for initial fix) 144 | @param utc UTC time, with ns precision (leap seconds are ignored) 145 | @return success if timestamp was read and time reference could be refreshed 146 | 147 | Set systime to 0 in ref to trigger initial synchronization. 148 | */ 149 | int lgw_gps_sync(struct tref* ref, uint32_t count_us, struct timespec utc); 150 | 151 | /** 152 | @brief Convert concentrator timestamp counter value to UTC time 153 | 154 | @param ref time reference structure required for time conversion 155 | @param count_us internal timestamp counter of the LoRa concentrator 156 | @param utc pointer to store UTC time, with ns precision (leap seconds ignored) 157 | @return success if the function was able to convert timestamp to UTC 158 | 159 | This function is typically used when a packet is received to transform the 160 | internal counter-based timestamp in an absolute timestamp with an accuracy in 161 | the order of a couple microseconds (ns resolution). 162 | */ 163 | int lgw_cnt2utc(struct tref ref, uint32_t count_us, struct timespec* utc); 164 | 165 | /** 166 | @brief Convert UTC time to concentrator timestamp counter value 167 | 168 | @param ref time reference structure required for time conversion 169 | @param utc UTC time, with ns precision (leap seconds are ignored) 170 | @param count_us pointer to store internal timestamp counter of LoRa concentrator 171 | @return success if the function was able to convert UTC to timestamp 172 | 173 | This function is typically used when a packet must be sent at an accurate time 174 | (eg. to send a piggy-back response after receiving a packet from a node) to 175 | transform an absolute UTC time into a matching internal concentrator timestamp. 176 | */ 177 | int lgw_utc2cnt(struct tref ref,struct timespec utc, uint32_t* count_us); 178 | 179 | #endif 180 | 181 | /* --- EOF ------------------------------------------------------------------ */ 182 | -------------------------------------------------------------------------------- /libloragw/inc/loragw_hal.h: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | LoRa concentrator Hardware Abstraction Layer 11 | 12 | License: Revised BSD License, see LICENSE.TXT file include in the project 13 | Maintainer: Sylvain Miermont 14 | */ 15 | 16 | 17 | #ifndef _LORAGW_HAL_H 18 | #define _LORAGW_HAL_H 19 | 20 | /* -------------------------------------------------------------------------- */ 21 | /* --- DEPENDANCIES --------------------------------------------------------- */ 22 | 23 | #include /* C99 types */ 24 | #include /* bool type */ 25 | 26 | #include "config.h" /* library configuration options (dynamically generated) */ 27 | 28 | /* -------------------------------------------------------------------------- */ 29 | /* --- PUBLIC MACROS -------------------------------------------------------- */ 30 | 31 | #define IS_LORA_BW(bw) ((bw == BW_125KHZ) || (bw == BW_250KHZ) || (bw == BW_500KHZ)) 32 | #define IS_LORA_STD_DR(dr) ((dr == DR_LORA_SF7) || (dr == DR_LORA_SF8) || (dr == DR_LORA_SF9) || (dr == DR_LORA_SF10) || (dr == DR_LORA_SF11) || (dr == DR_LORA_SF12)) 33 | #define IS_LORA_MULTI_DR(dr) ((dr & ~DR_LORA_MULTI) == 0) /* ones outside of DR_LORA_MULTI bitmask -> not a combination of LoRa datarates */ 34 | #define IS_LORA_CR(cr) ((cr == CR_LORA_4_5) || (cr == CR_LORA_4_6) || (cr == CR_LORA_4_7) || (cr == CR_LORA_4_8)) 35 | 36 | #define IS_FSK_BW(bw) ((bw >= 1) && (bw <= 7)) 37 | #define IS_FSK_DR(dr) ((dr >= DR_FSK_MIN) && (dr <= DR_FSK_MAX)) 38 | 39 | #define IS_TX_MODE(mode) ((mode == IMMEDIATE) || (mode == TIMESTAMPED) || (mode == ON_GPS)) 40 | 41 | /* -------------------------------------------------------------------------- */ 42 | /* --- PUBLIC CONSTANTS ----------------------------------------------------- */ 43 | 44 | /* return status code */ 45 | #define LGW_HAL_SUCCESS 0 46 | #define LGW_HAL_ERROR -1 47 | 48 | /* radio-specific parameters */ 49 | #define LGW_XTAL_FREQU 32000000 /* frequency of the RF reference oscillator */ 50 | #define LGW_RF_CHAIN_NB 2 /* number of RF chains */ 51 | #define LGW_RF_RX_BANDWIDTH { 1000000, 1000000} /* bandwidth of the radios */ 52 | 53 | /* type of if_chain + modem */ 54 | #define IF_UNDEFINED 0 55 | #define IF_LORA_STD 0x10 /* if + standard single-SF LoRa modem */ 56 | #define IF_LORA_MULTI 0x11 /* if + LoRa receiver with multi-SF capability */ 57 | #define IF_FSK_STD 0x20 /* if + standard FSK modem */ 58 | 59 | /* concentrator chipset-specific parameters */ 60 | /* to use array parameters, declare a local const and use 'if_chain' as index */ 61 | #define LGW_IF_CHAIN_NB 10 /* number of IF+modem RX chains */ 62 | #define LGW_PKT_FIFO_SIZE 8 /* depth of the RX packet FIFO */ 63 | #define LGW_DATABUFF_SIZE 1024 /* size in bytes of the RX data buffer (contains payload & metadata) */ 64 | #define LGW_REF_BW 125000 /* typical bandwidth of data channel */ 65 | #define LGW_MULTI_NB 8 /* number of LoRa 'multi SF' chains */ 66 | #define LGW_IFMODEM_CONFIG {\ 67 | IF_LORA_MULTI, \ 68 | IF_LORA_MULTI, \ 69 | IF_LORA_MULTI, \ 70 | IF_LORA_MULTI, \ 71 | IF_LORA_MULTI, \ 72 | IF_LORA_MULTI, \ 73 | IF_LORA_MULTI, \ 74 | IF_LORA_MULTI, \ 75 | IF_LORA_STD, \ 76 | IF_FSK_STD } /* configuration of available IF chains and modems on the hardware */ 77 | 78 | /* values available for the 'modulation' parameters */ 79 | /* NOTE: arbitrary values */ 80 | #define MOD_UNDEFINED 0 81 | #define MOD_LORA 0x10 82 | #define MOD_FSK 0x20 83 | 84 | /* values available for the 'bandwidth' parameters (LoRa & FSK) */ 85 | /* NOTE: directly encode FSK RX bandwidth, do not change */ 86 | #define BW_UNDEFINED 0 87 | #define BW_500KHZ 0x01 88 | #define BW_250KHZ 0x02 89 | #define BW_125KHZ 0x03 90 | #define BW_62K5HZ 0x04 91 | #define BW_31K2HZ 0x05 92 | #define BW_15K6HZ 0x06 93 | #define BW_7K8HZ 0x07 94 | 95 | /* values available for the 'datarate' parameters */ 96 | /* NOTE: LoRa values used directly to code SF bitmask in 'multi' modem, do not change */ 97 | #define DR_UNDEFINED 0 98 | #define DR_LORA_SF7 0x02 99 | #define DR_LORA_SF8 0x04 100 | #define DR_LORA_SF9 0x08 101 | #define DR_LORA_SF10 0x10 102 | #define DR_LORA_SF11 0x20 103 | #define DR_LORA_SF12 0x40 104 | #define DR_LORA_MULTI 0x7E 105 | /* NOTE: for FSK directly use baudrate between 500 bauds and 250 kbauds */ 106 | #define DR_FSK_MIN 500 107 | #define DR_FSK_MAX 250000 108 | 109 | /* values available for the 'coderate' parameters (LoRa only) */ 110 | /* NOTE: arbitrary values */ 111 | #define CR_UNDEFINED 0 112 | #define CR_LORA_4_5 0x01 113 | #define CR_LORA_4_6 0x02 114 | #define CR_LORA_4_7 0x03 115 | #define CR_LORA_4_8 0x04 116 | 117 | /* values available for the 'status' parameter */ 118 | /* NOTE: values according to hardware specification */ 119 | #define STAT_UNDEFINED 0x00 120 | #define STAT_NO_CRC 0x01 121 | #define STAT_CRC_BAD 0x11 122 | #define STAT_CRC_OK 0x10 123 | 124 | /* values available for the 'tx_mode' parameter */ 125 | #define IMMEDIATE 0 126 | #define TIMESTAMPED 1 127 | #define ON_GPS 2 128 | //#define ON_EVENT 3 129 | //#define GPS_DELAYED 4 130 | //#define EVENT_DELAYED 5 131 | 132 | /* values available for 'select' in the status function */ 133 | #define TX_STATUS 1 134 | #define RX_STATUS 2 135 | 136 | /* status code for TX_STATUS */ 137 | /* NOTE: arbitrary values */ 138 | #define TX_STATUS_UNKNOWN 0 139 | #define TX_OFF 1 /* TX modem disabled, it will ignore commands */ 140 | #define TX_FREE 2 /* TX modem is free, ready to receive a command */ 141 | #define TX_SCHEDULED 3 /* TX modem is loaded, ready to send the packet after an event and/or delay */ 142 | #define TX_EMITTING 4 /* TX modem is emitting */ 143 | 144 | /* status code for RX_STATUS */ 145 | /* NOTE: arbitrary values */ 146 | #define RX_STATUS_UNKNOWN 0 147 | #define RX_OFF 1 /* RX modem is disabled, it will ignore commands */ 148 | #define RX_ON 2 /* RX modem is receiving */ 149 | #define RX_SUSPENDED 3 /* RX is suspended while a TX is ongoing */ 150 | 151 | /* Maximum size of Tx gain LUT */ 152 | #define TX_GAIN_LUT_SIZE_MAX 36 153 | 154 | /* -------------------------------------------------------------------------- */ 155 | /* --- PUBLIC TYPES --------------------------------------------------------- */ 156 | 157 | enum lgw_radio_type_e { 158 | LGW_RADIO_TYPE_NONE, 159 | LGW_RADIO_TYPE_SX1255, 160 | LGW_RADIO_TYPE_SX1257 161 | }; 162 | 163 | /** 164 | @struct lgw_conf_board_s 165 | @brief Configuration structure for board specificities 166 | */ 167 | struct lgw_conf_board_s { 168 | bool lorawan_public; /*!> Enable ONLY for *public* networks using the LoRa MAC protocol */ 169 | uint8_t clksrc; /*!> Index of RF chain which provides clock to concentrator */ 170 | }; 171 | 172 | /** 173 | @struct lgw_conf_rxrf_s 174 | @brief Configuration structure for a RF chain 175 | */ 176 | struct lgw_conf_rxrf_s { 177 | bool enable; /*!> enable or disable that RF chain */ 178 | uint32_t freq_hz; /*!> center frequency of the radio in Hz */ 179 | float rssi_offset; /*!> Board-specific RSSI correction factor */ 180 | enum lgw_radio_type_e type; /*!> Radio type for that RF chain (SX1255, SX1257....) */ 181 | bool tx_enable; /*!> enable or disable TX on that RF chain */ 182 | }; 183 | 184 | /** 185 | @struct lgw_conf_rxif_s 186 | @brief Configuration structure for an IF chain 187 | */ 188 | struct lgw_conf_rxif_s { 189 | bool enable; /*!> enable or disable that IF chain */ 190 | uint8_t rf_chain; /*!> to which RF chain is that IF chain associated */ 191 | int32_t freq_hz; /*!> center frequ of the IF chain, relative to RF chain frequency */ 192 | uint8_t bandwidth; /*!> RX bandwidth, 0 for default */ 193 | uint32_t datarate; /*!> RX datarate, 0 for default */ 194 | uint8_t sync_word_size; /*!> size of FSK sync word (number of bytes, 0 for default) */ 195 | uint64_t sync_word; /*!> FSK sync word (ALIGN RIGHT, eg. 0xC194C1) */ 196 | }; 197 | 198 | /** 199 | @struct lgw_pkt_rx_s 200 | @brief Structure containing the metadata of a packet that was received and a pointer to the payload 201 | */ 202 | struct lgw_pkt_rx_s { 203 | uint32_t freq_hz; /*!> central frequency of the IF chain */ 204 | uint8_t if_chain; /*!> by which IF chain was packet received */ 205 | uint8_t status; /*!> status of the received packet */ 206 | uint32_t count_us; /*!> internal concentrator counter for timestamping, 1 microsecond resolution */ 207 | uint8_t rf_chain; /*!> through which RF chain the packet was received */ 208 | uint8_t modulation; /*!> modulation used by the packet */ 209 | uint8_t bandwidth; /*!> modulation bandwidth (LoRa only) */ 210 | uint32_t datarate; /*!> RX datarate of the packet (SF for LoRa) */ 211 | uint8_t coderate; /*!> error-correcting code of the packet (LoRa only) */ 212 | float rssi; /*!> average packet RSSI in dB */ 213 | float snr; /*!> average packet SNR, in dB (LoRa only) */ 214 | float snr_min; /*!> minimum packet SNR, in dB (LoRa only) */ 215 | float snr_max; /*!> maximum packet SNR, in dB (LoRa only) */ 216 | uint16_t crc; /*!> CRC that was received in the payload */ 217 | uint16_t size; /*!> payload size in bytes */ 218 | uint8_t payload[256]; /*!> buffer containing the payload */ 219 | }; 220 | 221 | /** 222 | @struct lgw_pkt_tx_s 223 | @brief Structure containing the configuration of a packet to send and a pointer to the payload 224 | */ 225 | struct lgw_pkt_tx_s { 226 | uint32_t freq_hz; /*!> center frequency of TX */ 227 | uint8_t tx_mode; /*!> select on what event/time the TX is triggered */ 228 | uint32_t count_us; /*!> timestamp or delay in microseconds for TX trigger */ 229 | uint8_t rf_chain; /*!> through which RF chain will the packet be sent */ 230 | int8_t rf_power; /*!> TX power, in dBm */ 231 | uint8_t modulation; /*!> modulation to use for the packet */ 232 | uint8_t bandwidth; /*!> modulation bandwidth (LoRa only) */ 233 | uint32_t datarate; /*!> TX datarate (baudrate for FSK, SF for LoRa) */ 234 | uint8_t coderate; /*!> error-correcting code of the packet (LoRa only) */ 235 | bool invert_pol; /*!> invert signal polarity, for orthogonal downlinks (LoRa only) */ 236 | uint8_t f_dev; /*!> frequency deviation, in kHz (FSK only) */ 237 | uint16_t preamble; /*!> set the preamble length, 0 for default */ 238 | bool no_crc; /*!> if true, do not send a CRC in the packet */ 239 | bool no_header; /*!> if true, enable implicit header mode (LoRa), fixed length (FSK) */ 240 | uint16_t size; /*!> payload size in bytes */ 241 | uint8_t payload[256]; /*!> buffer containing the payload */ 242 | }; 243 | 244 | /** 245 | @struct lgw_tx_gain_s 246 | @brief Structure containing all gains of Tx chain 247 | */ 248 | struct lgw_tx_gain_s { 249 | uint8_t dig_gain; /*!> 2 bits, control of the digital gain of SX1301 */ 250 | uint8_t pa_gain; /*!> 2 bits, control of the external PA (SX1301 I/O) */ 251 | uint8_t dac_gain; /*!> 2 bits, control of the radio DAC */ 252 | uint8_t mix_gain; /*!> 4 bits, control of the radio mixer */ 253 | int8_t rf_power; /*!> measured TX power at the board connector, in dBm */ 254 | }; 255 | 256 | /** 257 | @struct lgw_tx_gain_lut_s 258 | @brief Structure defining the Tx gain LUT 259 | */ 260 | struct lgw_tx_gain_lut_s { 261 | struct lgw_tx_gain_s lut[TX_GAIN_LUT_SIZE_MAX]; /*!> Array of Tx gain struct */ 262 | uint8_t size; /*!> Number of LUT indexes */ 263 | }; 264 | 265 | 266 | /* -------------------------------------------------------------------------- */ 267 | /* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */ 268 | 269 | /** 270 | @brief Configure the gateway board 271 | @param conf structure containing the configuration parameters 272 | @return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else 273 | */ 274 | int lgw_board_setconf(struct lgw_conf_board_s conf); 275 | 276 | /** 277 | @brief Configure an RF chain (must configure before start) 278 | @param rf_chain number of the RF chain to configure [0, LGW_RF_CHAIN_NB - 1] 279 | @param conf structure containing the configuration parameters 280 | @return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else 281 | */ 282 | int lgw_rxrf_setconf(uint8_t rf_chain, struct lgw_conf_rxrf_s conf); 283 | 284 | /** 285 | @brief Configure an IF chain + modem (must configure before start) 286 | @param if_chain number of the IF chain + modem to configure [0, LGW_IF_CHAIN_NB - 1] 287 | @param conf structure containing the configuration parameters 288 | @return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else 289 | */ 290 | int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf); 291 | 292 | /** 293 | @brief Configure the Tx gain LUT 294 | @param pointer to structure defining the LUT 295 | @return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else 296 | */ 297 | int lgw_txgain_setconf(struct lgw_tx_gain_lut_s *conf); 298 | 299 | /** 300 | @brief Connect to the LoRa concentrator, reset it and configure it according to previously set parameters 301 | @return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else 302 | */ 303 | int lgw_start(void); 304 | 305 | /** 306 | @brief Stop the LoRa concentrator and disconnect it 307 | @return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else 308 | */ 309 | int lgw_stop(void); 310 | 311 | /** 312 | @brief A non-blocking function that will fetch up to 'max_pkt' packets from the LoRa concentrator FIFO and data buffer 313 | @param max_pkt maximum number of packet that must be retrieved (equal to the size of the array of struct) 314 | @param pkt_data pointer to an array of struct that will receive the packet metadata and payload pointers 315 | @return LGW_HAL_ERROR id the operation failed, else the number of packets retrieved 316 | */ 317 | int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data); 318 | 319 | /** 320 | @brief Schedule a packet to be send immediately or after a delay depending on tx_mode 321 | @param pkt_data structure containing the data and metadata for the packet to send 322 | @return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else 323 | 324 | /!\ When sending a packet, there is a 1.5 ms delay for the analog circuitry to start and be stable (TX_START_DELAY). 325 | In 'timestamp' mode, this is transparent: the modem is started 1.5ms before the user-set timestamp value is reached, the preamble of the packet start right when the internal timestamp counter reach target value. 326 | In 'immediate' mode, the packet is emitted as soon as possible: transferring the packet (and its parameters) from the host to the concentrator takes some time, then there is the TX_START_DELAY, then the packet is emitted. 327 | In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is emitted 1.5ms after a rising edge of the trigger signal. Because there is no way to anticipate the triggering event and start the analog circuitry beforehand, that delay must be taken into account in the protocol. 328 | */ 329 | int lgw_send(struct lgw_pkt_tx_s pkt_data); 330 | 331 | /** 332 | @brief Give the the status of different part of the LoRa concentrator 333 | @param select is used to select what status we want to know 334 | @param code is used to return the status code 335 | @return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else 336 | */ 337 | int lgw_status(uint8_t select, uint8_t *code); 338 | 339 | /** 340 | @brief Abort a currently scheduled or ongoing TX 341 | @return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else 342 | */ 343 | int lgw_abort_tx(void); 344 | 345 | /** 346 | @brief Return value of internal counter when latest event (eg GPS pulse) was captured 347 | @param trig_cnt_us pointer to receive timestamp value 348 | @return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else 349 | */ 350 | int lgw_get_trigcnt(uint32_t* trig_cnt_us); 351 | 352 | /** 353 | @brief Allow user to check the version/options of the library once compiled 354 | @return pointer on a human-readable null terminated string 355 | */ 356 | const char* lgw_version_info(void); 357 | 358 | #endif 359 | 360 | /* --- EOF ------------------------------------------------------------------ */ 361 | -------------------------------------------------------------------------------- /libloragw/inc/loragw_reg.h: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Functions used to handle a single 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: Sylvain Miermont 17 | */ 18 | 19 | 20 | #ifndef _LORAGW_REG_H 21 | #define _LORAGW_REG_H 22 | 23 | /* -------------------------------------------------------------------------- */ 24 | /* --- DEPENDANCIES --------------------------------------------------------- */ 25 | 26 | #include /* C99 types */ 27 | #include /* bool type */ 28 | 29 | #include "config.h" /* library configuration options (dynamically generated) */ 30 | 31 | /* -------------------------------------------------------------------------- */ 32 | /* --- PUBLIC CONSTANTS ----------------------------------------------------- */ 33 | 34 | #define LGW_REG_SUCCESS 0 35 | #define LGW_REG_ERROR -1 36 | 37 | /* 38 | auto generated register mapping for C code : 11-Jul-2013 13:20:40 39 | this file contains autogenerated C struct used to access the LORA registers 40 | this file is autogenerated from registers description 41 | 293 registers are defined 42 | */ 43 | 44 | #define LGW_PAGE_REG 0 45 | #define LGW_SOFT_RESET 1 46 | #define LGW_VERSION 2 47 | #define LGW_RX_DATA_BUF_ADDR 3 48 | #define LGW_RX_DATA_BUF_DATA 4 49 | #define LGW_TX_DATA_BUF_ADDR 5 50 | #define LGW_TX_DATA_BUF_DATA 6 51 | #define LGW_CAPTURE_RAM_ADDR 7 52 | #define LGW_CAPTURE_RAM_DATA 8 53 | #define LGW_MCU_PROM_ADDR 9 54 | #define LGW_MCU_PROM_DATA 10 55 | #define LGW_RX_PACKET_DATA_FIFO_NUM_STORED 11 56 | #define LGW_RX_PACKET_DATA_FIFO_ADDR_POINTER 12 57 | #define LGW_RX_PACKET_DATA_FIFO_STATUS 13 58 | #define LGW_RX_PACKET_DATA_FIFO_PAYLOAD_SIZE 14 59 | #define LGW_MBWSSF_MODEM_ENABLE 15 60 | #define LGW_CONCENTRATOR_MODEM_ENABLE 16 61 | #define LGW_FSK_MODEM_ENABLE 17 62 | #define LGW_GLOBAL_EN 18 63 | #define LGW_CLK32M_EN 19 64 | #define LGW_CLKHS_EN 20 65 | #define LGW_START_BIST0 21 66 | #define LGW_START_BIST1 22 67 | #define LGW_CLEAR_BIST0 23 68 | #define LGW_CLEAR_BIST1 24 69 | #define LGW_BIST0_FINISHED 25 70 | #define LGW_BIST1_FINISHED 26 71 | #define LGW_MCU_AGC_PROG_RAM_BIST_STATUS 27 72 | #define LGW_MCU_ARB_PROG_RAM_BIST_STATUS 28 73 | #define LGW_CAPTURE_RAM_BIST_STATUS 29 74 | #define LGW_CHAN_FIR_RAM0_BIST_STATUS 30 75 | #define LGW_CHAN_FIR_RAM1_BIST_STATUS 31 76 | #define LGW_CORR0_RAM_BIST_STATUS 32 77 | #define LGW_CORR1_RAM_BIST_STATUS 33 78 | #define LGW_CORR2_RAM_BIST_STATUS 34 79 | #define LGW_CORR3_RAM_BIST_STATUS 35 80 | #define LGW_CORR4_RAM_BIST_STATUS 36 81 | #define LGW_CORR5_RAM_BIST_STATUS 37 82 | #define LGW_CORR6_RAM_BIST_STATUS 38 83 | #define LGW_CORR7_RAM_BIST_STATUS 39 84 | #define LGW_MODEM0_RAM0_BIST_STATUS 40 85 | #define LGW_MODEM1_RAM0_BIST_STATUS 41 86 | #define LGW_MODEM2_RAM0_BIST_STATUS 42 87 | #define LGW_MODEM3_RAM0_BIST_STATUS 43 88 | #define LGW_MODEM4_RAM0_BIST_STATUS 44 89 | #define LGW_MODEM5_RAM0_BIST_STATUS 45 90 | #define LGW_MODEM6_RAM0_BIST_STATUS 46 91 | #define LGW_MODEM7_RAM0_BIST_STATUS 47 92 | #define LGW_MODEM0_RAM1_BIST_STATUS 48 93 | #define LGW_MODEM1_RAM1_BIST_STATUS 49 94 | #define LGW_MODEM2_RAM1_BIST_STATUS 50 95 | #define LGW_MODEM3_RAM1_BIST_STATUS 51 96 | #define LGW_MODEM4_RAM1_BIST_STATUS 52 97 | #define LGW_MODEM5_RAM1_BIST_STATUS 53 98 | #define LGW_MODEM6_RAM1_BIST_STATUS 54 99 | #define LGW_MODEM7_RAM1_BIST_STATUS 55 100 | #define LGW_MODEM0_RAM2_BIST_STATUS 56 101 | #define LGW_MODEM1_RAM2_BIST_STATUS 57 102 | #define LGW_MODEM2_RAM2_BIST_STATUS 58 103 | #define LGW_MODEM3_RAM2_BIST_STATUS 59 104 | #define LGW_MODEM4_RAM2_BIST_STATUS 60 105 | #define LGW_MODEM5_RAM2_BIST_STATUS 61 106 | #define LGW_MODEM6_RAM2_BIST_STATUS 62 107 | #define LGW_MODEM7_RAM2_BIST_STATUS 63 108 | #define LGW_MODEM_MBWSSF_RAM0_BIST_STATUS 64 109 | #define LGW_MODEM_MBWSSF_RAM1_BIST_STATUS 65 110 | #define LGW_MODEM_MBWSSF_RAM2_BIST_STATUS 66 111 | #define LGW_MCU_AGC_DATA_RAM_BIST0_STATUS 67 112 | #define LGW_MCU_AGC_DATA_RAM_BIST1_STATUS 68 113 | #define LGW_MCU_ARB_DATA_RAM_BIST0_STATUS 69 114 | #define LGW_MCU_ARB_DATA_RAM_BIST1_STATUS 70 115 | #define LGW_TX_TOP_RAM_BIST0_STATUS 71 116 | #define LGW_TX_TOP_RAM_BIST1_STATUS 72 117 | #define LGW_DATA_MNGT_RAM_BIST0_STATUS 73 118 | #define LGW_DATA_MNGT_RAM_BIST1_STATUS 74 119 | #define LGW_GPIO_SELECT_INPUT 75 120 | #define LGW_GPIO_SELECT_OUTPUT 76 121 | #define LGW_GPIO_MODE 77 122 | #define LGW_GPIO_PIN_REG_IN 78 123 | #define LGW_GPIO_PIN_REG_OUT 79 124 | #define LGW_MCU_AGC_STATUS 80 125 | #define LGW_MCU_ARB_STATUS 81 126 | #define LGW_CHIP_ID 82 127 | #define LGW_EMERGENCY_FORCE_HOST_CTRL 83 128 | #define LGW_RX_INVERT_IQ 84 129 | #define LGW_MODEM_INVERT_IQ 85 130 | #define LGW_MBWSSF_MODEM_INVERT_IQ 86 131 | #define LGW_RX_EDGE_SELECT 87 132 | #define LGW_MISC_RADIO_EN 88 133 | #define LGW_FSK_MODEM_INVERT_IQ 89 134 | #define LGW_FILTER_GAIN 90 135 | #define LGW_RADIO_SELECT 91 136 | #define LGW_IF_FREQ_0 92 137 | #define LGW_IF_FREQ_1 93 138 | #define LGW_IF_FREQ_2 94 139 | #define LGW_IF_FREQ_3 95 140 | #define LGW_IF_FREQ_4 96 141 | #define LGW_IF_FREQ_5 97 142 | #define LGW_IF_FREQ_6 98 143 | #define LGW_IF_FREQ_7 99 144 | #define LGW_IF_FREQ_8 100 145 | #define LGW_IF_FREQ_9 101 146 | #define LGW_CHANN_OVERRIDE_AGC_GAIN 102 147 | #define LGW_CHANN_AGC_GAIN 103 148 | #define LGW_CORR0_DETECT_EN 104 149 | #define LGW_CORR1_DETECT_EN 105 150 | #define LGW_CORR2_DETECT_EN 106 151 | #define LGW_CORR3_DETECT_EN 107 152 | #define LGW_CORR4_DETECT_EN 108 153 | #define LGW_CORR5_DETECT_EN 109 154 | #define LGW_CORR6_DETECT_EN 110 155 | #define LGW_CORR7_DETECT_EN 111 156 | #define LGW_CORR_SAME_PEAKS_OPTION_SF6 112 157 | #define LGW_CORR_SAME_PEAKS_OPTION_SF7 113 158 | #define LGW_CORR_SAME_PEAKS_OPTION_SF8 114 159 | #define LGW_CORR_SAME_PEAKS_OPTION_SF9 115 160 | #define LGW_CORR_SAME_PEAKS_OPTION_SF10 116 161 | #define LGW_CORR_SAME_PEAKS_OPTION_SF11 117 162 | #define LGW_CORR_SAME_PEAKS_OPTION_SF12 118 163 | #define LGW_CORR_SIG_NOISE_RATIO_SF6 119 164 | #define LGW_CORR_SIG_NOISE_RATIO_SF7 120 165 | #define LGW_CORR_SIG_NOISE_RATIO_SF8 121 166 | #define LGW_CORR_SIG_NOISE_RATIO_SF9 122 167 | #define LGW_CORR_SIG_NOISE_RATIO_SF10 123 168 | #define LGW_CORR_SIG_NOISE_RATIO_SF11 124 169 | #define LGW_CORR_SIG_NOISE_RATIO_SF12 125 170 | #define LGW_CORR_NUM_SAME_PEAK 126 171 | #define LGW_CORR_MAC_GAIN 127 172 | #define LGW_ADJUST_MODEM_START_OFFSET_RDX4 128 173 | #define LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4 129 174 | #define LGW_DBG_CORR_SELECT_SF 130 175 | #define LGW_DBG_CORR_SELECT_CHANNEL 131 176 | #define LGW_DBG_DETECT_CPT 132 177 | #define LGW_DBG_SYMB_CPT 133 178 | #define LGW_CHIRP_INVERT_RX 134 179 | #define LGW_DC_NOTCH_EN 135 180 | #define LGW_IMPLICIT_CRC_EN 136 181 | #define LGW_IMPLICIT_CODING_RATE 137 182 | #define LGW_IMPLICIT_PAYLOAD_LENGHT 138 183 | #define LGW_FREQ_TO_TIME_INVERT 139 184 | #define LGW_FREQ_TO_TIME_DRIFT 140 185 | #define LGW_PAYLOAD_FINE_TIMING_GAIN 141 186 | #define LGW_PREAMBLE_FINE_TIMING_GAIN 142 187 | #define LGW_TRACKING_INTEGRAL 143 188 | #define LGW_FRAME_SYNCH_PEAK1_POS 144 189 | #define LGW_FRAME_SYNCH_PEAK2_POS 145 190 | #define LGW_PREAMBLE_SYMB1_NB 146 191 | #define LGW_FRAME_SYNCH_GAIN 147 192 | #define LGW_SYNCH_DETECT_TH 148 193 | #define LGW_LLR_SCALE 149 194 | #define LGW_SNR_AVG_CST 150 195 | #define LGW_PPM_OFFSET 151 196 | #define LGW_MAX_PAYLOAD_LEN 152 197 | #define LGW_ONLY_CRC_EN 153 198 | #define LGW_ZERO_PAD 154 199 | #define LGW_DEC_GAIN_OFFSET 155 200 | #define LGW_CHAN_GAIN_OFFSET 156 201 | #define LGW_FORCE_HOST_RADIO_CTRL 157 202 | #define LGW_FORCE_HOST_FE_CTRL 158 203 | #define LGW_FORCE_DEC_FILTER_GAIN 159 204 | #define LGW_MCU_RST_0 160 205 | #define LGW_MCU_RST_1 161 206 | #define LGW_MCU_SELECT_MUX_0 162 207 | #define LGW_MCU_SELECT_MUX_1 163 208 | #define LGW_MCU_CORRUPTION_DETECTED_0 164 209 | #define LGW_MCU_CORRUPTION_DETECTED_1 165 210 | #define LGW_MCU_SELECT_EDGE_0 166 211 | #define LGW_MCU_SELECT_EDGE_1 167 212 | #define LGW_CHANN_SELECT_RSSI 168 213 | #define LGW_RSSI_BB_DEFAULT_VALUE 169 214 | #define LGW_RSSI_DEC_DEFAULT_VALUE 170 215 | #define LGW_RSSI_CHANN_DEFAULT_VALUE 171 216 | #define LGW_RSSI_BB_FILTER_ALPHA 172 217 | #define LGW_RSSI_DEC_FILTER_ALPHA 173 218 | #define LGW_RSSI_CHANN_FILTER_ALPHA 174 219 | #define LGW_IQ_MISMATCH_A_AMP_COEFF 175 220 | #define LGW_IQ_MISMATCH_A_PHI_COEFF 176 221 | #define LGW_IQ_MISMATCH_B_AMP_COEFF 177 222 | #define LGW_IQ_MISMATCH_B_SEL_I 178 223 | #define LGW_IQ_MISMATCH_B_PHI_COEFF 179 224 | #define LGW_TX_TRIG_IMMEDIATE 180 225 | #define LGW_TX_TRIG_DELAYED 181 226 | #define LGW_TX_TRIG_GPS 182 227 | #define LGW_TX_START_DELAY 183 228 | #define LGW_TX_FRAME_SYNCH_PEAK1_POS 184 229 | #define LGW_TX_FRAME_SYNCH_PEAK2_POS 185 230 | #define LGW_TX_RAMP_DURATION 186 231 | #define LGW_TX_OFFSET_I 187 232 | #define LGW_TX_OFFSET_Q 188 233 | #define LGW_TX_MODE 189 234 | #define LGW_TX_ZERO_PAD 190 235 | #define LGW_TX_EDGE_SELECT 191 236 | #define LGW_TX_EDGE_SELECT_TOP 192 237 | #define LGW_TX_GAIN 193 238 | #define LGW_TX_CHIRP_LOW_PASS 194 239 | #define LGW_TX_FCC_WIDEBAND 195 240 | #define LGW_TX_SWAP_IQ 196 241 | #define LGW_MBWSSF_IMPLICIT_HEADER 197 242 | #define LGW_MBWSSF_IMPLICIT_CRC_EN 198 243 | #define LGW_MBWSSF_IMPLICIT_CODING_RATE 199 244 | #define LGW_MBWSSF_IMPLICIT_PAYLOAD_LENGHT 200 245 | #define LGW_MBWSSF_AGC_FREEZE_ON_DETECT 201 246 | #define LGW_MBWSSF_FRAME_SYNCH_PEAK1_POS 202 247 | #define LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS 203 248 | #define LGW_MBWSSF_PREAMBLE_SYMB1_NB 204 249 | #define LGW_MBWSSF_FRAME_SYNCH_GAIN 205 250 | #define LGW_MBWSSF_SYNCH_DETECT_TH 206 251 | #define LGW_MBWSSF_DETECT_MIN_SINGLE_PEAK 207 252 | #define LGW_MBWSSF_DETECT_TRIG_SAME_PEAK_NB 208 253 | #define LGW_MBWSSF_FREQ_TO_TIME_INVERT 209 254 | #define LGW_MBWSSF_FREQ_TO_TIME_DRIFT 210 255 | #define LGW_MBWSSF_PPM_CORRECTION 211 256 | #define LGW_MBWSSF_PAYLOAD_FINE_TIMING_GAIN 212 257 | #define LGW_MBWSSF_PREAMBLE_FINE_TIMING_GAIN 213 258 | #define LGW_MBWSSF_TRACKING_INTEGRAL 214 259 | #define LGW_MBWSSF_ZERO_PAD 215 260 | #define LGW_MBWSSF_MODEM_BW 216 261 | #define LGW_MBWSSF_RADIO_SELECT 217 262 | #define LGW_MBWSSF_RX_CHIRP_INVERT 218 263 | #define LGW_MBWSSF_LLR_SCALE 219 264 | #define LGW_MBWSSF_SNR_AVG_CST 220 265 | #define LGW_MBWSSF_PPM_OFFSET 221 266 | #define LGW_MBWSSF_RATE_SF 222 267 | #define LGW_MBWSSF_ONLY_CRC_EN 223 268 | #define LGW_MBWSSF_MAX_PAYLOAD_LEN 224 269 | #define LGW_TX_STATUS 225 270 | #define LGW_FSK_CH_BW_EXPO 226 271 | #define LGW_FSK_RSSI_LENGTH 227 272 | #define LGW_FSK_RX_INVERT 228 273 | #define LGW_FSK_PKT_MODE 229 274 | #define LGW_FSK_PSIZE 230 275 | #define LGW_FSK_CRC_EN 231 276 | #define LGW_FSK_DCFREE_ENC 232 277 | #define LGW_FSK_CRC_IBM 233 278 | #define LGW_FSK_ERROR_OSR_TOL 234 279 | #define LGW_FSK_RADIO_SELECT 235 280 | #define LGW_FSK_BR_RATIO 236 281 | #define LGW_FSK_REF_PATTERN_LSB 237 282 | #define LGW_FSK_REF_PATTERN_MSB 238 283 | #define LGW_FSK_PKT_LENGTH 239 284 | #define LGW_FSK_TX_GAUSSIAN_EN 240 285 | #define LGW_FSK_TX_GAUSSIAN_SELECT_BT 241 286 | #define LGW_FSK_TX_PATTERN_EN 242 287 | #define LGW_FSK_TX_PREAMBLE_SEQ 243 288 | #define LGW_FSK_TX_PSIZE 244 289 | #define LGW_FSK_NODE_ADRS 245 290 | #define LGW_FSK_BROADCAST 246 291 | #define LGW_FSK_AUTO_AFC_ON 247 292 | #define LGW_FSK_PATTERN_TIMEOUT_CFG 248 293 | #define LGW_SPI_RADIO_A__DATA 249 294 | #define LGW_SPI_RADIO_A__DATA_READBACK 250 295 | #define LGW_SPI_RADIO_A__ADDR 251 296 | #define LGW_SPI_RADIO_A__CS 252 297 | #define LGW_SPI_RADIO_B__DATA 253 298 | #define LGW_SPI_RADIO_B__DATA_READBACK 254 299 | #define LGW_SPI_RADIO_B__ADDR 255 300 | #define LGW_SPI_RADIO_B__CS 256 301 | #define LGW_RADIO_A_EN 257 302 | #define LGW_RADIO_B_EN 258 303 | #define LGW_RADIO_RST 259 304 | #define LGW_LNA_A_EN 260 305 | #define LGW_PA_A_EN 261 306 | #define LGW_LNA_B_EN 262 307 | #define LGW_PA_B_EN 263 308 | #define LGW_PA_GAIN 264 309 | #define LGW_LNA_A_CTRL_LUT 265 310 | #define LGW_PA_A_CTRL_LUT 266 311 | #define LGW_LNA_B_CTRL_LUT 267 312 | #define LGW_PA_B_CTRL_LUT 268 313 | #define LGW_CAPTURE_SOURCE 269 314 | #define LGW_CAPTURE_START 270 315 | #define LGW_CAPTURE_FORCE_TRIGGER 271 316 | #define LGW_CAPTURE_WRAP 272 317 | #define LGW_CAPTURE_PERIOD 273 318 | #define LGW_MODEM_STATUS 274 319 | #define LGW_VALID_HEADER_COUNTER_0 275 320 | #define LGW_VALID_PACKET_COUNTER_0 276 321 | #define LGW_VALID_HEADER_COUNTER_MBWSSF 277 322 | #define LGW_VALID_HEADER_COUNTER_FSK 278 323 | #define LGW_VALID_PACKET_COUNTER_MBWSSF 279 324 | #define LGW_VALID_PACKET_COUNTER_FSK 280 325 | #define LGW_CHANN_RSSI 281 326 | #define LGW_BB_RSSI 282 327 | #define LGW_DEC_RSSI 283 328 | #define LGW_DBG_MCU_DATA 284 329 | #define LGW_DBG_ARB_MCU_RAM_DATA 285 330 | #define LGW_DBG_AGC_MCU_RAM_DATA 286 331 | #define LGW_NEXT_PACKET_CNT 287 332 | #define LGW_ADDR_CAPTURE_COUNT 288 333 | #define LGW_TIMESTAMP 289 334 | #define LGW_DBG_CHANN0_GAIN 290 335 | #define LGW_DBG_CHANN1_GAIN 291 336 | #define LGW_DBG_CHANN2_GAIN 292 337 | #define LGW_DBG_CHANN3_GAIN 293 338 | #define LGW_DBG_CHANN4_GAIN 294 339 | #define LGW_DBG_CHANN5_GAIN 295 340 | #define LGW_DBG_CHANN6_GAIN 296 341 | #define LGW_DBG_CHANN7_GAIN 297 342 | #define LGW_DBG_DEC_FILT_GAIN 298 343 | #define LGW_SPI_DATA_FIFO_PTR 299 344 | #define LGW_PACKET_DATA_FIFO_PTR 300 345 | #define LGW_DBG_ARB_MCU_RAM_ADDR 301 346 | #define LGW_DBG_AGC_MCU_RAM_ADDR 302 347 | #define LGW_SPI_MASTER_CHIP_SELECT_POLARITY 303 348 | #define LGW_SPI_MASTER_CPOL 304 349 | #define LGW_SPI_MASTER_CPHA 305 350 | #define LGW_SIG_GEN_ANALYSER_MUX_SEL 306 351 | #define LGW_SIG_GEN_EN 307 352 | #define LGW_SIG_ANALYSER_EN 308 353 | #define LGW_SIG_ANALYSER_AVG_LEN 309 354 | #define LGW_SIG_ANALYSER_PRECISION 310 355 | #define LGW_SIG_ANALYSER_VALID_OUT 311 356 | #define LGW_SIG_GEN_FREQ 312 357 | #define LGW_SIG_ANALYSER_FREQ 313 358 | #define LGW_SIG_ANALYSER_I_OUT 314 359 | #define LGW_SIG_ANALYSER_Q_OUT 315 360 | #define LGW_GPS_EN 316 361 | #define LGW_GPS_POL 317 362 | #define LGW_SW_TEST_REG1 318 363 | #define LGW_SW_TEST_REG2 319 364 | #define LGW_SW_TEST_REG3 320 365 | #define LGW_DATA_MNGT_STATUS 321 366 | #define LGW_DATA_MNGT_CPT_FRAME_ALLOCATED 322 367 | #define LGW_DATA_MNGT_CPT_FRAME_FINISHED 323 368 | #define LGW_DATA_MNGT_CPT_FRAME_READEN 324 369 | #define LGW_TX_TRIG_ALL 325 370 | 371 | #define LGW_TOTALREGS 326 372 | 373 | /* -------------------------------------------------------------------------- */ 374 | /* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */ 375 | 376 | /** 377 | @brief Connect LoRa concentrator by opening SPI link 378 | @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) 379 | */ 380 | int lgw_connect(void); 381 | 382 | /** 383 | @brief Disconnect LoRa concentrator by closing SPI link 384 | @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) 385 | */ 386 | int lgw_disconnect(void); 387 | 388 | /** 389 | @brief Use the soft-reset register to put the concentrator in initial state 390 | @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) 391 | */ 392 | int lgw_soft_reset(void); 393 | 394 | /** 395 | @brief Check if the registers are ok, send diagnostics to stdio/stderr/file 396 | @param f file descriptor to to which the check result will be written 397 | @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) 398 | */ 399 | int lgw_reg_check(FILE *f); 400 | 401 | /** 402 | @brief LoRa concentrator register write 403 | @param register_id register number in the data structure describing registers 404 | @param reg_value signed value to write to the register (for u32, use cast) 405 | @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) 406 | */ 407 | int lgw_reg_w(uint16_t register_id, int32_t reg_value); 408 | 409 | /** 410 | @brief LoRa concentrator register read 411 | @param register_id register number in the data structure describing registers 412 | @param reg_value pointer to a variable where to write register read value 413 | @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) 414 | */ 415 | int lgw_reg_r(uint16_t register_id, int32_t *reg_value); 416 | 417 | /** 418 | @brief LoRa concentrator register burst write 419 | @param register_id register number in the data structure describing registers 420 | @param data pointer to byte array that will be sent to the LoRa concentrator 421 | @param size size of the transfer, in byte(s) 422 | @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) 423 | */ 424 | int lgw_reg_wb(uint16_t register_id, uint8_t *data, uint16_t size); 425 | 426 | /** 427 | @brief LoRa concentrator register burst read 428 | @param register_id register number in the data structure describing registers 429 | @param data pointer to byte array that will be written from the LoRa concentrator 430 | @param size size of the transfer, in byte(s) 431 | @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) 432 | */ 433 | int lgw_reg_rb(uint16_t register_id, uint8_t *data, uint16_t size); 434 | 435 | 436 | #endif 437 | 438 | /* --- EOF ------------------------------------------------------------------ */ 439 | -------------------------------------------------------------------------------- /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 | /* -------------------------------------------------------------------------- */ 39 | /* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */ 40 | 41 | /** 42 | @brief LoRa concentrator SPI setup (configure I/O and peripherals) 43 | @param spi_target_ptr pointer on a generic pointer to SPI target (implementation dependant) 44 | @return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR) 45 | */ 46 | 47 | int lgw_spi_open(void **spi_target_ptr); 48 | 49 | /** 50 | @brief LoRa concentrator SPI close 51 | @param spi_target 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_close(void *spi_target); 56 | 57 | /** 58 | @brief LoRa concentrator SPI single-byte write 59 | @param spi_target generic pointer to SPI target (implementation dependant) 60 | @param address 7-bit register address 61 | @param data data byte to write 62 | @return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR) 63 | */ 64 | int lgw_spi_w(void *spi_target, uint8_t address, uint8_t data); 65 | 66 | /** 67 | @brief LoRa concentrator SPI single-byte read 68 | @param spi_target generic pointer to SPI target (implementation dependant) 69 | @param address 7-bit register address 70 | @param data data byte to write 71 | @return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR) 72 | */ 73 | int lgw_spi_r(void *spi_target, uint8_t address, uint8_t *data); 74 | 75 | /** 76 | @brief LoRa concentrator SPI burst (multiple-byte) write 77 | @param spi_target generic pointer to SPI target (implementation dependant) 78 | @param address 7-bit register address 79 | @param data pointer to byte array that will be sent to the LoRa concentrator 80 | @param size size of the transfer, in byte(s) 81 | @return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR) 82 | */ 83 | int lgw_spi_wb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size); 84 | 85 | /** 86 | @brief LoRa concentrator SPI burst (multiple-byte) read 87 | @param spi_target generic pointer to SPI target (implementation dependant) 88 | @param address 7-bit register address 89 | @param data pointer to byte array that will be written from the LoRa concentrator 90 | @param size size of the transfer, in byte(s) 91 | @return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR) 92 | */ 93 | int lgw_spi_rb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size); 94 | 95 | #endif 96 | 97 | /* --- EOF ------------------------------------------------------------------ */ 98 | -------------------------------------------------------------------------------- /libloragw/install_ftdi.txt: -------------------------------------------------------------------------------- 1 | # / _____) _ | | 2 | # ( (____ _____ ____ _| |_ _____ ____| |__ 3 | # \____ \| ___ | (_ _) ___ |/ ___) _ \ 4 | # _____) ) ____| | | || |_| ____( (___| | | | 5 | # (______/|_____)_|_|_| \__)_____)\____)_| |_| 6 | # (C)2013 Semtech-Cycleo 7 | # 8 | # Description: 9 | # Installation procedure for FTDI SPI-over-USB dependencies 10 | 11 | # [STEP 1] Install libftdi 12 | sudo apt-get install libftdi-dev 13 | 14 | # this should install : 15 | # - libftdi-dev 0.19-4 (armhf) 16 | # - libftdil 0.19-4 (armhf) 17 | # - libusb-dev 2:0.1.12-20 (armhf) 18 | 19 | # [STEP 2] Download and unpack the libMPSSE 1.3 20 | # File must match SHA1 Checksum: 1b994a23b118f83144261e3e786c43df74a81cd5 21 | wget http://libmpsse.googlecode.com/files/libmpsse-1.3.tar.gz 22 | sha1sum libmpsse-1.3.tar.gz 23 | tar -xzvf libmpsse-1.3.tar.gz 24 | 25 | # Go to the src directory and install the library 26 | ./configure --disable-python 27 | make 28 | sudo make install 29 | # Static and dynamic libraries compiled code is put into /usr/local/lib 30 | # Header file is put into /usr/local/include 31 | 32 | # On the Pcduino, you must regenerate the library cache (might some time). 33 | sudo ldconfig 34 | 35 | # [STEP 3] to allow non-root applications to access the FTDI device on USB 36 | # copy the provided 99-libftdi.rules file in /etc/udev/rules.d 37 | # For the nano board, only the FT2232H line is required. 38 | # Non-root users members of plugdev group will be able to access the device. 39 | 40 | # [STEP 4] Unpack the LoRa Gateway project and go to its directory. 41 | # Configure build options in library.cfg, then build the library and examples. 42 | make all 43 | 44 | # [STEP 5] Connect a nanoconcentrator and run test_loragw_reg to test that 45 | # you have access to LoRa registers. 46 | # Less than 50 registers of the ~300 registers should return a mismatch. 47 | -------------------------------------------------------------------------------- /libloragw/library.cfg: -------------------------------------------------------------------------------- 1 | # That file will be included in the Makefile files that have hardware dependencies 2 | 3 | ### SPI interface to the concentrator ### 4 | # Accepted values: 5 | # native Linux native SPI driver (RECOMMENDED). 6 | # Note: check the value of /dev/spidevX.X defined in source code 7 | # to ensure the right device will be opened on your platform. 8 | # ftdi FTDI SPI-over-USB bridge using libmpsse/libftdi/libusb 9 | 10 | CFG_SPI= ftdi 11 | 12 | ### Debug options ### 13 | # Set the DEBUG_* to 1 to activate debug mode in individual modules. 14 | # Warning: that makes the module *very verbose*, do not use for production 15 | 16 | DEBUG_AUX= 0 17 | DEBUG_SPI= 0 18 | DEBUG_REG= 0 19 | DEBUG_HAL= 0 20 | DEBUG_GPS= 0 21 | -------------------------------------------------------------------------------- /libloragw/obj/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirakonta/lora_gateway/0642acb11d56150f619d76f809fdfa48280df80e/libloragw/obj/.gitkeep -------------------------------------------------------------------------------- /libloragw/readme.md: -------------------------------------------------------------------------------- 1 | / _____) _ | | 2 | ( (____ _____ ____ _| |_ _____ ____| |__ 3 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 4 | _____) ) ____| | | || |_| ____( (___| | | | 5 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 6 | (C)2013 Semtech-Cycleo 7 | 8 | LoRa concentrator HAL user manual 9 | ============================ 10 | 11 | 1. Introduction 12 | --------------- 13 | 14 | The LoRa concentrator Hardware Abstraction Layer is a C library that allow you 15 | to use a Semtech concentrator chip through a reduced number of high level C 16 | functions to configure the hardware, send and receive packets. 17 | 18 | The Semtech LoRa concentrator is a digital multi-channel multi-standard packet 19 | radio used to send and receive packets wirelessly using LoRa or FSK modulations. 20 | 21 | 2. Components of the library 22 | ---------------------------- 23 | 24 | The library is composed of 5 modules: 25 | 26 | * loragw_hal 27 | * loragw_reg 28 | * loragw_spi 29 | * loragw_aux 30 | * loragw_gps 31 | 32 | The library also contains 4 test programs to demonstrate code use and check 33 | functionality. 34 | 35 | ### 2.1. loragw_hal ### 36 | 37 | This is the main module and contains the high level functions to configure and 38 | use the LoRa concentrator: 39 | 40 | * lgw_board_setconf, to set the configuration of the concentrator 41 | * lgw_rxrf_setconf, to set the configuration of the radio channels 42 | * lgw_rxif_setconf, to set the configuration of the IF+modem channels 43 | * lgw_txgain_setconf, to set the configuration of the concentrator gain table 44 | * lgw_start, to apply the set configuration to the hardware and start it 45 | * lgw_stop, to stop the hardware 46 | * lgw_receive, to fetch packets if any was received 47 | * lgw_send, to send a single packet (non-blocking, see warning in usage section) 48 | * lgw_status, to check when a packet has effectively been sent 49 | 50 | For an standard application, include only this module. 51 | The use of this module is detailed on the usage section. 52 | 53 | /!\ When sending a packet, there is a 1.5 ms delay for the analog circuitry to 54 | start and be stable (TX_START_DELAY). 55 | 56 | In 'timestamp' mode, this is transparent: the modem is started 1.5ms before the 57 | user-set timestamp value is reached, the preamble of the packet start right when 58 | the internal timestamp counter reach target value. 59 | 60 | In 'immediate' mode, the packet is emitted as soon as possible: transferring the 61 | packet (and its parameters) from the host to the concentrator takes some time, 62 | then there is the TX_START_DELAY, then the packet is emitted. 63 | 64 | In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is 65 | emitted 1.5ms after a rising edge of the trigger signal. Because there is no 66 | way to anticipate the triggering event and start the analog circuitry 67 | beforehand, that delay must be taken into account in the protocol. 68 | 69 | ### 2.2. loragw_reg ### 70 | 71 | This module is used to access to the LoRa concentrator registers by name instead 72 | of by address: 73 | 74 | * lgw_connect, to initialise and check the connection with the hardware 75 | * lgw_disconnect, to disconnect the hardware 76 | * lgw_soft_reset, to reset the whole hardware by resetting the register array 77 | * lgw_reg_check, to check all registers vs. their default value and output the 78 | result to a file 79 | * lgw_reg_r, read a named register 80 | * lgw_reg_w, write a named register 81 | * lgw_reg_rb, read a name register in burst 82 | * lgw_reg_wb, write a named register in burst 83 | 84 | This module handles pagination, read-only registers protection, multi-byte 85 | registers management, signed registers management, read-modify-write routines 86 | for sub-byte registers and read/write burst fragmentation to respect SPI 87 | maximum burst length constraints. 88 | 89 | It make the code much easier to read and to debug. 90 | Moreover, if registers are relocated between different hardware revisions but 91 | keep the same function, the code written using register names can be reused "as 92 | is". 93 | 94 | If you need access to all the registers, include this module in your 95 | application. 96 | 97 | **/!\ Warning** please be sure to have a good understanding of the LoRa 98 | concentrator inner working before accessing the internal registers directly. 99 | 100 | ### 2.3. loragw_spi ### 101 | 102 | This module contains the functions to access the LoRa concentrator register 103 | array through the SPI interface: 104 | 105 | * lgw_spi_r to read one byte 106 | * lgw_spi_w to write one byte 107 | * lgw_spi_rb to read two bytes or more 108 | * lgw_spi_wb to write two bytes or more 109 | 110 | Please *do not* include that module directly into your application. 111 | 112 | **/!\ Warning** Accessing the LoRa concentrator register array without the 113 | checks and safety provided by the functions in loragw_reg is not recommended. 114 | 115 | ### 2.4. loragw_aux ### 116 | 117 | This module contains a single host-dependant function wait_ms to pause for a 118 | defined amount of milliseconds. 119 | 120 | The procedure to start and configure the LoRa concentrator hardware contained in 121 | the loragw_hal module requires to wait for several milliseconds at certain 122 | steps, typically to allow for supply voltages or clocks to stabilize after been 123 | switched on. 124 | 125 | An accuracy of 1 ms or less is ideal. 126 | If your system does not allow that level of accuracy, make sure that the actual 127 | delay is *longer* that the time specified when the function is called (ie. 128 | wait_ms(X) **MUST NOT** before X milliseconds under any circumstance). 129 | 130 | If the minimum delays are not guaranteed during the configuration and start 131 | procedure, the hardware might not work at nominal performance. 132 | Most likely, it will not work at all. 133 | 134 | ### 2.5. loragw_gps ### 135 | 136 | This module contains functions to synchronize the concentrator internal 137 | counter with an absolute time reference, in our case a GPS satellite receiver. 138 | 139 | The internal concentrator counter is used to timestamp incoming packets and to 140 | triggers outgoing packets with a microsecond accuracy. 141 | In some cases, it might be useful to be able to transform that internal 142 | timestamp (that is independent for each concentrator running in a typical 143 | networked system) into an absolute UTC time. 144 | 145 | In a typical implementation a GPS specific thread will be called, doing the 146 | following things after opening the serial port: 147 | 148 | * blocking reads on the serial port (using system read() function) 149 | * parse NMEA sentences (using lgw_parse_nmea) 150 | 151 | And each time an RMC sentence has been received: 152 | 153 | * get the concentrator timestamp (using lgw_get_trigcnt, mutex needed to 154 | protect access to the concentrator) 155 | * get the UTC time contained in the NMEA sentence (using lgw_gps_get) 156 | * call the lgw_gps_sync function (use mutex to protect the time reference that 157 | should be a global shared variable). 158 | 159 | Then, in other threads, you can simply used that continuously adjusted time 160 | reference to convert internal timestamps to UTC time (using lgw_cnt2utc) or 161 | the other way around (using lgw_utc2cnt). 162 | 163 | 3. Software build process 164 | -------------------------- 165 | 166 | ### 3.1. Details of the software ### 167 | 168 | The library is written following ANSI C conventions but using C99 explicit 169 | length data type for all data exchanges with hardware and for parameters. 170 | 171 | The loragw_aux module contains POSIX dependant functions for millisecond 172 | accuracy pause. 173 | For embedded platforms, the function could be rewritten using hardware timers. 174 | 175 | ### 3.2. Building options ### 176 | 177 | All modules use a fprintf(stderr,...) function to display debug diagnostic 178 | messages if the DEBUG_xxx is set to 1 in library.cfg 179 | 180 | The other settings available in library.cfg are: 181 | 182 | * CFG_SPI configures how the link between the host and the concentrator chip 183 | is done. It is highly recommended to use native SPI instead of FTDI when possible 184 | for permormance reasons. 185 | Note: when using native SPI on linux host, ensure that the /dev/spidevX.X 186 | which is to be opened on your host is the same as the one defined in 187 | libloragw/src/loragw_spi.native.c 188 | 189 | ### 3.3. Building procedures ### 190 | 191 | For cross-compilation set the CROSS_COMPILE variable in the Makefile with the 192 | correct toolchain name. 193 | 194 | The Makefile in the libloragw directory will parse the library.cfg file and 195 | generate a config.h C header file containing #define options. 196 | Those options enables and disables sections of code in the loragw_xxx.h files 197 | and the *.c source files. 198 | 199 | The library.cfg is also used directly to select the proper set of dynamic 200 | libraries to be linked with. 201 | 202 | ### 3.4. Dynamic libraries requirements ### 203 | 204 | Depending on config, SPI module needs LibMPSSE to access the FTDI SPI-over-USB 205 | bridge. Please read install_ftdi.txt for installation instructions. 206 | 207 | The code was tested with version 1.3 of LibMPSSE: 208 | http://libmpsse.googlecode.com/files/libmpsse-1.3.tar.gz 209 | SHA1 Checksum: 1b994a23b118f83144261e3e786c43df74a81cd5 210 | 211 | ### 3.5. Export ### 212 | 213 | Once build, to use that library on another system, you need to export the 214 | following files : 215 | 216 | * libloragw/library.cfg -> root configuration file 217 | * libloragw/libloragw.a -> static library, to be linked with a program 218 | * libloragw/readme.md -> required for license compliance 219 | * libloragw/inc/config.h -> C configuration flags, derived from library.cfg 220 | * libloragw/inc/loragw_*.h -> take only the ones you need (eg. _hal and _gps) 221 | 222 | After statically linking the library to your application, only the license 223 | is required to be kept or copied inside your program documentation. 224 | 225 | 4. Hardware dependencies 226 | ------------------------ 227 | 228 | ### 4.1. Hardware revision ### 229 | 230 | The loragw_reg and loragw_hal are written for a specific version on the Semtech 231 | hardware (IP and/or silicon revision). 232 | 233 | This code has been written for: 234 | 235 | * Semtech SX1301 chip (or FPGA equivalent) 236 | * Semtech SX1257 or SX1255 I/Q transceivers 237 | 238 | The library will not work if there is a mismatch between the hardware version 239 | and the library version. You can use the test program test_loragw_reg to check 240 | if the hardware registers match their software declaration. 241 | 242 | ### 4.2. SPI communication ### 243 | 244 | loragw_spi contains 4 SPI functions (read, write, burst read, burst write) that 245 | are platform-dependant. 246 | The functions must be rewritten depending on the SPI bridge you use: 247 | 248 | * SPI master matched to the Linux SPI device driver (provided) 249 | * SPI over USB using FTDI components (provided) 250 | * native SPI using a microcontroller peripheral (not provided) 251 | 252 | Edit library.cfg to chose which SPI physical interface you want to use. 253 | 254 | You can use the test program test_loragw_spi to check with a logic analyser 255 | that the SPI communication is working 256 | 257 | ### 4.3. GPS receiver (or other GNSS system) ### 258 | 259 | To use the GPS module of the library, the host must be connected to a GPS 260 | receiver via a serial link (or an equivalent receiver using a different 261 | satellite constellation). 262 | The serial link must appear as a "tty" device in the /dev/ directory, and the 263 | user launching the program must have the proper system rights to read and 264 | write on that device. 265 | Use `chmod a+rw` to allow all users to access that specific tty device, or use 266 | sudo to run all your programs (eg. `sudo ./test_loragw_gps`). 267 | 268 | In the current revision, the library only reads data from the serial port, 269 | expecting to receive NMEA frames that are generally sent by GPS receivers as 270 | soon as they are powered up. 271 | 272 | The GPS receiver **MUST** send RMC NMEA sentences (starting with "$GRMC") shortly after sending a PPS pulse on to allow internal 274 | concentrator timestamps to be converted to absolute UTC time. 275 | If the GPS receiver sends a GGA sentence, the gateway 3D position will also be 276 | available. 277 | 278 | The PPS pulse must be sent to the pin 22 of connector CONN400 on the Semtech 279 | FPGA-based nano-concentrator board. Ground is available on pins 2 and 12 of 280 | the same connector. 281 | The pin is loaded by an FPGA internal pull-down, and the signal level coming 282 | in the FPGA must be 3.3V. 283 | Timing is captured on the rising edge of the PPS signal. 284 | 285 | 5. Usage 286 | -------- 287 | 288 | ### 5.1. Setting the software environment ### 289 | 290 | For a typical application you need to: 291 | 292 | * include loragw_hal.h in your program source 293 | * link to the libloragw.a static library during compilation 294 | * link to the librt library due to loragw_aux dependencies (timing functions) 295 | * link to the libmpsse library if you use a FTDI SPI-over-USB bridge 296 | 297 | For an application that will also access the concentrator configuration 298 | registers directly (eg. for advanced configuration) you also need to: 299 | 300 | * include loragw_reg.h in your program source 301 | 302 | ### 5.2. Using the software API ### 303 | 304 | To use the HAL in your application, you must follow some basic rules: 305 | 306 | * configure the radios path and IF+modem path before starting the radio 307 | * the configuration is only transferred to hardware when you call the *start* 308 | function 309 | * you cannot receive packets until one (or +) radio is enabled AND one (or +) 310 | IF+modem part is enabled AND the concentrator is started 311 | * you cannot send packets until one (or +) radio is enabled AND the concentrator 312 | is started 313 | * you must stop the concentrator before changing the configuration 314 | 315 | A typical application flow for using the HAL is the following: 316 | 317 | 318 | 319 | loop { 320 | 321 | 322 | 323 | } 324 | 325 | 326 | **/!\ Warning** The lgw_send function is non-blocking and returns while the 327 | LoRa concentrator is still sending the packet, or even before the packet has 328 | started to be transmitted if the packet is triggered on a future event. 329 | While a packet is emitted, no packet can be received (limitation intrinsic to 330 | most radio frequency systems). 331 | 332 | Your application *must* take into account the time it takes to send a packet or 333 | check the status (using lgw_status) before attempting to send another packet. 334 | 335 | Trying to send a packet while the previous packet has not finished being send 336 | will result in the previous packet not being sent or being sent only partially 337 | (resulting in a CRC error in the receiver). 338 | 339 | ### 5.3. Debugging mode ### 340 | 341 | To debug your application, it might help to compile the loragw_hal function 342 | with the debug messages activated (set DEBUG_HAL=1 in library.cfg). 343 | It then send a lot of details, including detailed error messages to *stderr*. 344 | 345 | 6. License 346 | ----------- 347 | 348 | Copyright (c) 2013, SEMTECH S.A. 349 | All rights reserved. 350 | 351 | Redistribution and use in source and binary forms, with or without 352 | modification, are permitted provided that the following conditions are met: 353 | 354 | * Redistributions of source code must retain the above copyright 355 | notice, this list of conditions and the following disclaimer. 356 | * Redistributions in binary form must reproduce the above copyright 357 | notice, this list of conditions and the following disclaimer in the 358 | documentation and/or other materials provided with the distribution. 359 | * Neither the name of the Semtech corporation nor the 360 | names of its contributors may be used to endorse or promote products 361 | derived from this software without specific prior written permission. 362 | 363 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 364 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 365 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 366 | DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY 367 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 368 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 369 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 370 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 371 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 372 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 373 | 374 | *EOF* 375 | -------------------------------------------------------------------------------- /libloragw/src/loragw_aux.c: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | LoRa concentrator HAL auxiliary functions 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 /* 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 | void wait_ms(unsigned long a) { 46 | struct timespec dly; 47 | struct timespec rem; 48 | 49 | dly.tv_sec = a / 1000; 50 | dly.tv_nsec = ((long)a % 1000) * 1000000; 51 | 52 | DEBUG_PRINTF("NOTE dly: %ld sec %ld ns\n", dly.tv_sec, dly.tv_nsec); 53 | 54 | if((dly.tv_sec > 0) || ((dly.tv_sec == 0) && (dly.tv_nsec > 100000))) { 55 | clock_nanosleep(CLOCK_MONOTONIC, 0, &dly, &rem); 56 | DEBUG_PRINTF("NOTE remain: %ld sec %ld ns\n", rem.tv_sec, rem.tv_nsec); 57 | } 58 | return; 59 | } 60 | 61 | /* --- EOF ------------------------------------------------------------------ */ 62 | -------------------------------------------------------------------------------- /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 18 | */ 19 | 20 | 21 | /* -------------------------------------------------------------------------- */ 22 | /* --- DEPENDANCIES --------------------------------------------------------- */ 23 | 24 | #include /* C99 types */ 25 | #include /* printf fprintf */ 26 | #include /* malloc free */ 27 | #include /* memcpy */ 28 | 29 | #include 30 | 31 | #include "loragw_spi.h" 32 | 33 | /* -------------------------------------------------------------------------- */ 34 | /* --- PRIVATE MACROS ------------------------------------------------------- */ 35 | 36 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 37 | #if DEBUG_SPI == 1 38 | #define DEBUG_MSG(str) fprintf(stderr, str) 39 | #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) 40 | #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_SPI_ERROR;} 41 | #else 42 | #define DEBUG_MSG(str) 43 | #define DEBUG_PRINTF(fmt, args...) 44 | #define CHECK_NULL(a) if(a==NULL){return LGW_SPI_ERROR;} 45 | #endif 46 | 47 | /* -------------------------------------------------------------------------- */ 48 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ 49 | 50 | #define READ_ACCESS 0x00 51 | #define WRITE_ACCESS 0x80 52 | 53 | /* parameters for a FT232H */ 54 | #define VID 0x0403 55 | #define PID 0x6014 56 | 57 | /* -------------------------------------------------------------------------- */ 58 | /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ 59 | 60 | /* SPI initialization and configuration */ 61 | int lgw_spi_open(void **spi_target_ptr) { 62 | struct mpsse_context *mpsse = NULL; 63 | int a, b; 64 | 65 | /* check input variables */ 66 | CHECK_NULL(spi_target_ptr); /* cannot be null, must point on a void pointer (*spi_target_ptr can be null) */ 67 | 68 | /* try to open the first available FTDI device matching VID/PID parameters */ 69 | mpsse = OpenIndex(VID,PID,SPI0, SIX_MHZ, MSB, IFACE_A, NULL, NULL, 0); 70 | if (mpsse == NULL) { 71 | DEBUG_MSG("ERROR: MPSSE OPEN FUNCTION RETURNED NULL\n"); 72 | return LGW_SPI_ERROR; 73 | } 74 | if (mpsse->open != 1) { 75 | DEBUG_MSG("ERROR: MPSSE OPEN FUNCTION FAILED\n"); 76 | return LGW_SPI_ERROR; 77 | } 78 | 79 | /* toggle pin ADBUS5 of the FT232H */ 80 | /* On the MTAC-LORA, it resets the SX1301 */ 81 | a = PinLow(mpsse, GPIOL1); 82 | b = PinHigh(mpsse, GPIOL1); 83 | if ((a != MPSSE_OK) || (b != MPSSE_OK)) { 84 | DEBUG_MSG("ERROR: IMPOSSIBLE TO TOGGLE GPIOL1/ADBUS5\n"); 85 | return LGW_SPI_ERROR; 86 | } 87 | 88 | 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()); 89 | *spi_target_ptr = (void *)mpsse; 90 | return LGW_SPI_SUCCESS; 91 | } 92 | 93 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 94 | 95 | /* SPI release */ 96 | int lgw_spi_close(void *spi_target) { 97 | struct mpsse_context *mpsse = spi_target; 98 | 99 | /* check input variables */ 100 | CHECK_NULL(spi_target); 101 | 102 | Close(mpsse); 103 | 104 | /* close return no status, assume success (0_o) */ 105 | return LGW_SPI_SUCCESS; 106 | } 107 | 108 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 109 | 110 | /* Simple write */ 111 | /* transaction time: .6 to 1 ms typically */ 112 | int lgw_spi_w(void *spi_target, uint8_t address, uint8_t data) { 113 | struct mpsse_context *mpsse = spi_target; 114 | uint8_t out_buf[2]; 115 | int a, b, c; 116 | 117 | /* check input variables */ 118 | CHECK_NULL(spi_target); 119 | if ((address & 0x80) != 0) { 120 | DEBUG_MSG("WARNING: SPI address > 127\n"); 121 | } 122 | 123 | /* prepare frame to be sent */ 124 | out_buf[0] = WRITE_ACCESS | (address & 0x7F); 125 | out_buf[1] = data; 126 | 127 | /* MPSSE transaction */ 128 | a = Start(mpsse); 129 | b = FastWrite(mpsse, (char *)out_buf, 2); 130 | c = Stop(mpsse); 131 | 132 | /* determine return code */ 133 | if ((a != MPSSE_OK) || (b != MPSSE_OK) || (c != MPSSE_OK)) { 134 | DEBUG_MSG("ERROR: SPI WRITE FAILURE\n"); 135 | return LGW_SPI_ERROR; 136 | } else { 137 | DEBUG_MSG("Note: SPI write success\n"); 138 | return LGW_SPI_SUCCESS; 139 | } 140 | } 141 | 142 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 143 | 144 | /* Simple read (using Transfer function) */ 145 | /* transaction time: 1.1 to 2 ms typically */ 146 | int lgw_spi_r(void *spi_target, uint8_t address, uint8_t *data) { 147 | struct mpsse_context *mpsse = spi_target; 148 | uint8_t out_buf[2]; 149 | uint8_t *in_buf = NULL; 150 | int a, b; 151 | 152 | /* check input variables */ 153 | CHECK_NULL(spi_target); 154 | if ((address & 0x80) != 0) { 155 | DEBUG_MSG("WARNING: SPI address > 127\n"); 156 | } 157 | CHECK_NULL(data); 158 | 159 | /* prepare frame to be sent */ 160 | out_buf[0] = READ_ACCESS | (address & 0x7F); 161 | out_buf[1] = 0x00; 162 | 163 | /* MPSSE transaction */ 164 | a = Start(mpsse); 165 | in_buf = (uint8_t *)Transfer(mpsse, (char *)out_buf, 2); 166 | b = Stop(mpsse); 167 | 168 | /* determine return code */ 169 | if ((in_buf == NULL) || (a != MPSSE_OK) || (b != MPSSE_OK)) { 170 | DEBUG_MSG("ERROR: SPI READ FAILURE\n"); 171 | if (in_buf != NULL) { 172 | free(in_buf); 173 | } 174 | return LGW_SPI_ERROR; 175 | } else { 176 | DEBUG_MSG("Note: SPI read success\n"); 177 | *data = in_buf[1]; 178 | free(in_buf); 179 | return LGW_SPI_SUCCESS; 180 | } 181 | } 182 | 183 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 184 | 185 | /* Burst (multiple-byte) write */ 186 | /* transaction time: 3.7ms for 2500 data bytes @6MHz, 1kB chunks */ 187 | /* transaction time: 0.5ms for 16 data bytes @6MHz, 1kB chunks */ 188 | int lgw_spi_wb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) { 189 | struct mpsse_context *mpsse = spi_target; 190 | uint8_t command; 191 | uint8_t *out_buf = NULL; 192 | int size_to_do, buf_size, chunk_size, offset; 193 | int a=0, b=0, c=0; 194 | int i; 195 | 196 | /* check input parameters */ 197 | CHECK_NULL(spi_target); 198 | if ((address & 0x80) != 0) { 199 | DEBUG_MSG("WARNING: SPI address > 127\n"); 200 | } 201 | CHECK_NULL(data); 202 | if (size == 0) { 203 | DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); 204 | return LGW_SPI_ERROR; 205 | } 206 | 207 | /* prepare command byte */ 208 | command = WRITE_ACCESS | (address & 0x7F); 209 | size_to_do = size + 1; /* add a byte for the address */ 210 | 211 | /* allocate data buffer */ 212 | buf_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; 213 | out_buf = malloc(buf_size); 214 | if (out_buf == NULL) { 215 | DEBUG_MSG("ERROR: MALLOC FAIL\n"); 216 | return LGW_SPI_ERROR; 217 | } 218 | 219 | /* start MPSSE transaction */ 220 | a = Start(mpsse); 221 | for (i=0; size_to_do > 0; ++i) { 222 | chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; 223 | if (i == 0) { 224 | /* first chunk, need to append the address */ 225 | out_buf[0] = command; 226 | memcpy(out_buf+1, data, chunk_size-1); 227 | } else { 228 | /* following chunks, just copy the data */ 229 | offset = (i * LGW_BURST_CHUNK) - 1; 230 | memcpy(out_buf, data + offset, chunk_size); 231 | } 232 | b = FastWrite(mpsse, (char *)out_buf, chunk_size); 233 | size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ 234 | } 235 | c = Stop(mpsse); 236 | 237 | /* deallocate data buffer */ 238 | free(out_buf); 239 | 240 | /* determine return code (only the last FastWrite is checked) */ 241 | if ((a != MPSSE_OK) || (b != MPSSE_OK) || (c != MPSSE_OK)) { 242 | DEBUG_MSG("ERROR: SPI BURST WRITE FAILURE\n"); 243 | return LGW_SPI_ERROR; 244 | } else { 245 | DEBUG_MSG("Note: SPI burst write success\n"); 246 | return LGW_SPI_SUCCESS; 247 | } 248 | } 249 | 250 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 251 | 252 | /* Burst (multiple-byte) read (using FastWrite & FastRead functions) */ 253 | /* transaction time: 7-12ms for 2500 data bytes @6MHz, 1kB chunks */ 254 | /* transaction time: 2ms for 16 data bytes @6MHz, 1kB chunks */ 255 | int lgw_spi_rb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) { 256 | struct mpsse_context *mpsse = spi_target; 257 | uint8_t command; 258 | int size_to_do, chunk_size, offset; 259 | int a=0, b=0, c=0, d=0; 260 | int i; 261 | 262 | /* check input parameters */ 263 | CHECK_NULL(spi_target); 264 | if ((address & 0x80) != 0) { 265 | DEBUG_MSG("WARNING: SPI address > 127\n"); 266 | } 267 | CHECK_NULL(data); 268 | if (size == 0) { 269 | DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); 270 | return LGW_SPI_ERROR; 271 | } 272 | 273 | /* prepare command byte */ 274 | command = READ_ACCESS | (address & 0x7F); 275 | size_to_do = size; 276 | 277 | /* start MPSSE transaction */ 278 | a = Start(mpsse); 279 | b = FastWrite(mpsse, (char *)&command, 1); 280 | for (i=0; size_to_do > 0; ++i) { 281 | chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; 282 | offset = i * LGW_BURST_CHUNK; 283 | c = FastRead(mpsse, (char *)(data + offset), chunk_size); 284 | size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ 285 | } 286 | d = Stop(mpsse); 287 | 288 | /* determine return code (only the last FastRead is checked) */ 289 | if ((a != MPSSE_OK) || (b != MPSSE_OK) || (c != MPSSE_OK) || (d != MPSSE_OK)) { 290 | DEBUG_MSG("ERROR: SPI BURST READ FAILURE\n"); 291 | return LGW_SPI_ERROR; 292 | } else { 293 | DEBUG_MSG("Note: SPI burst read success\n"); 294 | return LGW_SPI_SUCCESS; 295 | } 296 | } 297 | 298 | /* --- EOF ------------------------------------------------------------------ */ 299 | -------------------------------------------------------------------------------- /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 | #define SPI_SPEED 8000000 57 | #define SPI_DEV_PATH "/dev/spidev0.0" 58 | //#define SPI_DEV_PATH "/dev/spidev32766.0" 59 | 60 | /* -------------------------------------------------------------------------- */ 61 | /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ 62 | 63 | /* SPI initialization and configuration */ 64 | int lgw_spi_open(void **spi_target_ptr) { 65 | int *spi_device = NULL; 66 | int dev; 67 | int a=0, b=0; 68 | int i; 69 | 70 | /* check input variables */ 71 | CHECK_NULL(spi_target_ptr); /* cannot be null, must point on a void pointer (*spi_target_ptr can be null) */ 72 | 73 | /* allocate memory for the device descriptor */ 74 | spi_device = malloc(sizeof(int)); 75 | if (spi_device == NULL) { 76 | DEBUG_MSG("ERROR: MALLOC FAIL\n"); 77 | return LGW_SPI_ERROR; 78 | } 79 | 80 | /* open SPI device */ 81 | dev = open(SPI_DEV_PATH, O_RDWR); 82 | if (dev < 0) { 83 | DEBUG_PRINTF("ERROR: failed to open SPI device %s\n", SPI_DEV_PATH); 84 | return LGW_SPI_ERROR; 85 | } 86 | 87 | /* setting SPI mode to 'mode 0' */ 88 | i = SPI_MODE_0; 89 | a = ioctl(dev, SPI_IOC_WR_MODE, &i); 90 | b = ioctl(dev, SPI_IOC_RD_MODE, &i); 91 | if ((a < 0) || (b < 0)) { 92 | DEBUG_MSG("ERROR: SPI PORT FAIL TO SET IN MODE 0\n"); 93 | close(dev); 94 | free(spi_device); 95 | return LGW_SPI_ERROR; 96 | } 97 | 98 | /* setting SPI max clk (in Hz) */ 99 | i = SPI_SPEED; 100 | a = ioctl(dev, SPI_IOC_WR_MAX_SPEED_HZ, &i); 101 | b = ioctl(dev, SPI_IOC_RD_MAX_SPEED_HZ, &i); 102 | if ((a < 0) || (b < 0)) { 103 | DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MAX SPEED\n"); 104 | close(dev); 105 | free(spi_device); 106 | return LGW_SPI_ERROR; 107 | } 108 | 109 | /* setting SPI to MSB first */ 110 | i = 0; 111 | a = ioctl(dev, SPI_IOC_WR_LSB_FIRST, &i); 112 | b = ioctl(dev, SPI_IOC_RD_LSB_FIRST, &i); 113 | if ((a < 0) || (b < 0)) { 114 | DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MSB FIRST\n"); 115 | close(dev); 116 | free(spi_device); 117 | return LGW_SPI_ERROR; 118 | } 119 | 120 | /* setting SPI to 8 bits per word */ 121 | i = 0; 122 | a = ioctl(dev, SPI_IOC_WR_BITS_PER_WORD, &i); 123 | b = ioctl(dev, SPI_IOC_RD_BITS_PER_WORD, &i); 124 | if ((a < 0) || (b < 0)) { 125 | DEBUG_MSG("ERROR: SPI PORT FAIL TO SET 8 BITS-PER-WORD\n"); 126 | close(dev); 127 | return LGW_SPI_ERROR; 128 | } 129 | 130 | *spi_device = dev; 131 | *spi_target_ptr = (void *)spi_device; 132 | DEBUG_MSG("Note: SPI port opened and configured ok\n"); 133 | return LGW_SPI_SUCCESS; 134 | } 135 | 136 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 137 | 138 | /* SPI release */ 139 | int lgw_spi_close(void *spi_target) { 140 | int spi_device; 141 | int a; 142 | 143 | /* check input variables */ 144 | CHECK_NULL(spi_target); 145 | 146 | /* close file & deallocate file descriptor */ 147 | spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ 148 | a = close(spi_device); 149 | free(spi_target); 150 | 151 | /* determine return code */ 152 | if (a < 0) { 153 | DEBUG_MSG("ERROR: SPI PORT FAILED TO CLOSE\n"); 154 | return LGW_SPI_ERROR; 155 | } else { 156 | DEBUG_MSG("Note: SPI port closed\n"); 157 | return LGW_SPI_SUCCESS; 158 | } 159 | } 160 | 161 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 162 | 163 | /* Simple write */ 164 | int lgw_spi_w(void *spi_target, uint8_t address, uint8_t data) { 165 | int spi_device; 166 | uint8_t out_buf[2]; 167 | struct spi_ioc_transfer k; 168 | int a; 169 | 170 | /* check input variables */ 171 | CHECK_NULL(spi_target); 172 | if ((address & 0x80) != 0) { 173 | DEBUG_MSG("WARNING: SPI address > 127\n"); 174 | } 175 | 176 | spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ 177 | 178 | /* prepare frame to be sent */ 179 | out_buf[0] = WRITE_ACCESS | (address & 0x7F); 180 | out_buf[1] = data; 181 | 182 | /* I/O transaction */ 183 | memset(&k, 0, sizeof(k)); /* clear k */ 184 | k.tx_buf = (unsigned long) out_buf; 185 | k.len = ARRAY_SIZE(out_buf); 186 | k.speed_hz = SPI_SPEED; 187 | k.cs_change = 1; 188 | k.bits_per_word = 8; 189 | a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); 190 | 191 | /* determine return code */ 192 | if (a != 2) { 193 | DEBUG_MSG("ERROR: SPI WRITE FAILURE\n"); 194 | return LGW_SPI_ERROR; 195 | } else { 196 | DEBUG_MSG("Note: SPI write success\n"); 197 | return LGW_SPI_SUCCESS; 198 | } 199 | } 200 | 201 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 202 | 203 | /* Simple read */ 204 | int lgw_spi_r(void *spi_target, uint8_t address, uint8_t *data) { 205 | int spi_device; 206 | uint8_t out_buf[2]; 207 | uint8_t in_buf[ARRAY_SIZE(out_buf)]; 208 | struct spi_ioc_transfer k; 209 | int a; 210 | 211 | /* check input variables */ 212 | CHECK_NULL(spi_target); 213 | if ((address & 0x80) != 0) { 214 | DEBUG_MSG("WARNING: SPI address > 127\n"); 215 | } 216 | CHECK_NULL(data); 217 | 218 | spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ 219 | 220 | /* prepare frame to be sent */ 221 | out_buf[0] = READ_ACCESS | (address & 0x7F); 222 | out_buf[1] = 0x00; 223 | 224 | /* I/O transaction */ 225 | memset(&k, 0, sizeof(k)); /* clear k */ 226 | k.tx_buf = (unsigned long) out_buf; 227 | k.rx_buf = (unsigned long) in_buf; 228 | k.len = ARRAY_SIZE(out_buf); 229 | k.cs_change = 1; 230 | a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); 231 | 232 | /* determine return code */ 233 | if (a != 2) { 234 | DEBUG_MSG("ERROR: SPI READ FAILURE\n"); 235 | return LGW_SPI_ERROR; 236 | } else { 237 | DEBUG_MSG("Note: SPI read success\n"); 238 | *data = in_buf[1]; 239 | return LGW_SPI_SUCCESS; 240 | } 241 | } 242 | 243 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 244 | 245 | /* Burst (multiple-byte) write */ 246 | int lgw_spi_wb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) { 247 | int spi_device; 248 | uint8_t command; 249 | struct spi_ioc_transfer k[2]; 250 | int size_to_do, chunk_size, offset; 251 | int byte_transfered = 0; 252 | int i; 253 | 254 | /* check input parameters */ 255 | CHECK_NULL(spi_target); 256 | if ((address & 0x80) != 0) { 257 | DEBUG_MSG("WARNING: SPI address > 127\n"); 258 | } 259 | CHECK_NULL(data); 260 | if (size == 0) { 261 | DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); 262 | return LGW_SPI_ERROR; 263 | } 264 | 265 | spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ 266 | 267 | /* prepare command byte */ 268 | command = WRITE_ACCESS | (address & 0x7F); 269 | size_to_do = size; 270 | 271 | /* I/O transaction */ 272 | memset(&k, 0, sizeof(k)); /* clear k */ 273 | k[0].tx_buf = (unsigned long) &command; 274 | k[0].len = 1; 275 | k[0].cs_change = 0; 276 | k[1].cs_change = 1; 277 | for (i=0; size_to_do > 0; ++i) { 278 | chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; 279 | offset = i * LGW_BURST_CHUNK; 280 | k[1].tx_buf = (unsigned long)(data + offset); 281 | k[1].len = chunk_size; 282 | byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - 1 ); 283 | DEBUG_PRINTF("BURST WRITE: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered); 284 | size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ 285 | } 286 | 287 | /* determine return code */ 288 | if (byte_transfered != size) { 289 | DEBUG_MSG("ERROR: SPI BURST WRITE FAILURE\n"); 290 | return LGW_SPI_ERROR; 291 | } else { 292 | DEBUG_MSG("Note: SPI burst write success\n"); 293 | return LGW_SPI_SUCCESS; 294 | } 295 | } 296 | 297 | /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 298 | 299 | /* Burst (multiple-byte) read */ 300 | int lgw_spi_rb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) { 301 | int spi_device; 302 | uint8_t command; 303 | struct spi_ioc_transfer k[2]; 304 | int size_to_do, chunk_size, offset; 305 | int byte_transfered = 0; 306 | int i; 307 | 308 | /* check input parameters */ 309 | CHECK_NULL(spi_target); 310 | if ((address & 0x80) != 0) { 311 | DEBUG_MSG("WARNING: SPI address > 127\n"); 312 | } 313 | CHECK_NULL(data); 314 | if (size == 0) { 315 | DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); 316 | return LGW_SPI_ERROR; 317 | } 318 | 319 | spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ 320 | 321 | /* prepare command byte */ 322 | command = READ_ACCESS | (address & 0x7F); 323 | size_to_do = size; 324 | 325 | /* I/O transaction */ 326 | memset(&k, 0, sizeof(k)); /* clear k */ 327 | k[0].tx_buf = (unsigned long) &command; 328 | k[0].len = 1; 329 | k[0].cs_change = 0; 330 | k[1].cs_change = 1; 331 | for (i=0; size_to_do > 0; ++i) { 332 | chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; 333 | offset = i * LGW_BURST_CHUNK; 334 | k[1].rx_buf = (unsigned long)(data + offset); 335 | k[1].len = chunk_size; 336 | byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - 1 ); 337 | DEBUG_PRINTF("BURST READ: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered); 338 | size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ 339 | } 340 | 341 | /* determine return code */ 342 | if (byte_transfered != size) { 343 | DEBUG_MSG("ERROR: SPI BURST READ FAILURE\n"); 344 | return LGW_SPI_ERROR; 345 | } else { 346 | DEBUG_MSG("Note: SPI burst read success\n"); 347 | return LGW_SPI_SUCCESS; 348 | } 349 | } 350 | 351 | /* --- EOF ------------------------------------------------------------------ */ 352 | -------------------------------------------------------------------------------- /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/ttyACM0", 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_hal.c: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Minimum test program for the loragw_hal '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 /* getopt access */ 33 | 34 | #include "loragw_hal.h" 35 | #include "loragw_reg.h" 36 | #include "loragw_aux.h" 37 | 38 | /* -------------------------------------------------------------------------- */ 39 | /* --- PRIVATE MACROS ------------------------------------------------------- */ 40 | 41 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 42 | 43 | /* -------------------------------------------------------------------------- */ 44 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ 45 | 46 | #define DEFAULT_RSSI_OFFSET 0.0 47 | 48 | /* -------------------------------------------------------------------------- */ 49 | /* --- PRIVATE VARIABLES ---------------------------------------------------- */ 50 | 51 | static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ 52 | static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */ 53 | 54 | /* -------------------------------------------------------------------------- */ 55 | /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ 56 | 57 | static void sig_handler(int sigio); 58 | 59 | /* -------------------------------------------------------------------------- */ 60 | /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ 61 | 62 | static void sig_handler(int sigio) { 63 | if (sigio == SIGQUIT) { 64 | quit_sig = 1;; 65 | } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { 66 | exit_sig = 1; 67 | } 68 | } 69 | 70 | /* describe command line options */ 71 | void usage(void) { 72 | printf("Library version information: %s\n", lgw_version_info()); 73 | printf( "Available options:\n"); 74 | printf( " -h print this help\n"); 75 | printf( " -a Radio A RX frequency in MHz\n"); 76 | printf( " -b Radio B RX frequency in MHz\n"); 77 | printf( " -t Radio TX frequency in MHz\n"); 78 | printf( " -r Radio type (SX1255:1255, SX1257:1257)\n"); 79 | printf( " -k Concentrator clock source (0: radio_A(default in MTAC-LORA), 1: radio_B)\n"); 80 | } 81 | 82 | /* -------------------------------------------------------------------------- */ 83 | /* --- MAIN FUNCTION -------------------------------------------------------- */ 84 | 85 | int main(int argc, char **argv) 86 | { 87 | struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ 88 | 89 | struct lgw_conf_board_s boardconf; 90 | struct lgw_conf_rxrf_s rfconf; 91 | struct lgw_conf_rxif_s ifconf; 92 | 93 | struct lgw_pkt_rx_s rxpkt[4]; /* array containing up to 4 inbound packets metadata */ 94 | struct lgw_pkt_tx_s txpkt; /* configuration and metadata for an outbound packet */ 95 | struct lgw_pkt_rx_s *p; /* pointer on a RX packet */ 96 | 97 | int i, j; 98 | int nb_pkt; 99 | uint32_t fa = 0, fb = 0, ft = 0; 100 | enum lgw_radio_type_e radio_type = LGW_RADIO_TYPE_NONE; 101 | uint8_t clocksource = 0; /* Radio A is source in MTAC-LORA */ 102 | 103 | uint32_t tx_cnt = 0; 104 | unsigned long loop_cnt = 0; 105 | uint8_t status_var = 0; 106 | double xd = 0.0; 107 | int xi = 0; 108 | 109 | /* parse command line options */ 110 | while ((i = getopt (argc, argv, "ha:b:t:r:k:")) != -1) { 111 | switch (i) { 112 | case 'h': 113 | usage(); 114 | return -1; 115 | break; 116 | case 'a': /* Radio A RX frequency in MHz */ 117 | sscanf(optarg, "%lf", &xd); 118 | fa = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ 119 | break; 120 | case 'b': /* Radio B RX frequency in MHz */ 121 | sscanf(optarg, "%lf", &xd); 122 | fb = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ 123 | break; 124 | case 't': /* Radio TX frequency in MHz */ 125 | sscanf(optarg, "%lf", &xd); 126 | ft = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ 127 | break; 128 | case 'r': /* Radio type (1255, 1257) */ 129 | sscanf(optarg, "%i", &xi); 130 | switch (xi) { 131 | case 1255: 132 | radio_type = LGW_RADIO_TYPE_SX1255; 133 | break; 134 | case 1257: 135 | radio_type = LGW_RADIO_TYPE_SX1257; 136 | break; 137 | default: 138 | printf("ERROR: invalid radio type\n"); 139 | usage(); 140 | return -1; 141 | } 142 | break; 143 | case 'k': /* Concentrator clock source (Radio A or Radio B) */ 144 | sscanf(optarg, "%i", &xi); 145 | clocksource = (uint8_t)xi; 146 | break; 147 | default: 148 | printf("ERROR: argument parsing\n"); 149 | usage(); 150 | return -1; 151 | } 152 | } 153 | 154 | /* check input parameters */ 155 | if ((fa == 0) || (fb == 0) || (ft == 0)) { 156 | printf("ERROR: missing frequency input parameter:\n"); 157 | printf(" Radio A RX: %u\n", fa); 158 | printf(" Radio B RX: %u\n", fb); 159 | printf(" Radio TX: %u\n", ft); 160 | usage(); 161 | return -1; 162 | } 163 | 164 | if (radio_type == LGW_RADIO_TYPE_NONE) { 165 | printf("ERROR: missing radio type parameter:\n"); 166 | usage(); 167 | return -1; 168 | } 169 | 170 | /* configure signal handling */ 171 | sigemptyset(&sigact.sa_mask); 172 | sigact.sa_flags = 0; 173 | sigact.sa_handler = sig_handler; 174 | sigaction(SIGQUIT, &sigact, NULL); 175 | sigaction(SIGINT, &sigact, NULL); 176 | sigaction(SIGTERM, &sigact, NULL); 177 | 178 | /* beginning of LoRa concentrator-specific code */ 179 | printf("Beginning of test for loragw_hal.c\n"); 180 | 181 | printf("*** Library version information ***\n%s\n\n", lgw_version_info()); 182 | 183 | /* set configuration for board */ 184 | memset(&boardconf, 0, sizeof(boardconf)); 185 | 186 | boardconf.lorawan_public = true; 187 | boardconf.clksrc = clocksource; 188 | lgw_board_setconf(boardconf); 189 | 190 | /* set configuration for RF chains */ 191 | memset(&rfconf, 0, sizeof(rfconf)); 192 | 193 | rfconf.enable = true; 194 | rfconf.freq_hz = fa; 195 | rfconf.rssi_offset = DEFAULT_RSSI_OFFSET; 196 | rfconf.type = radio_type; 197 | rfconf.tx_enable = true; 198 | lgw_rxrf_setconf(0, rfconf); /* radio A, f0 */ 199 | 200 | rfconf.enable = true; 201 | rfconf.freq_hz = fb; 202 | rfconf.rssi_offset = DEFAULT_RSSI_OFFSET; 203 | rfconf.type = radio_type; 204 | rfconf.tx_enable = false; 205 | lgw_rxrf_setconf(1, rfconf); /* radio B, f1 */ 206 | 207 | /* set configuration for LoRa multi-SF channels (bandwidth cannot be set) */ 208 | memset(&ifconf, 0, sizeof(ifconf)); 209 | 210 | ifconf.enable = true; 211 | ifconf.rf_chain = 0; 212 | ifconf.freq_hz = -300000; 213 | ifconf.datarate = DR_LORA_MULTI; 214 | lgw_rxif_setconf(0, ifconf); /* chain 0: LoRa 125kHz, all SF, on f0 - 0.3 MHz */ 215 | 216 | ifconf.enable = true; 217 | ifconf.rf_chain = 0; 218 | ifconf.freq_hz = 300000; 219 | ifconf.datarate = DR_LORA_MULTI; 220 | lgw_rxif_setconf(1, ifconf); /* chain 1: LoRa 125kHz, all SF, on f0 + 0.3 MHz */ 221 | 222 | ifconf.enable = true; 223 | ifconf.rf_chain = 1; 224 | ifconf.freq_hz = -300000; 225 | ifconf.datarate = DR_LORA_MULTI; 226 | lgw_rxif_setconf(2, ifconf); /* chain 2: LoRa 125kHz, all SF, on f1 - 0.3 MHz */ 227 | 228 | ifconf.enable = true; 229 | ifconf.rf_chain = 1; 230 | ifconf.freq_hz = 300000; 231 | ifconf.datarate = DR_LORA_MULTI; 232 | lgw_rxif_setconf(3, ifconf); /* chain 3: LoRa 125kHz, all SF, on f1 + 0.3 MHz */ 233 | 234 | ifconf.enable = true; 235 | ifconf.rf_chain = 0; 236 | ifconf.freq_hz = -100000; 237 | ifconf.datarate = DR_LORA_MULTI; 238 | lgw_rxif_setconf(4, ifconf); /* chain 4: LoRa 125kHz, all SF, on f0 - 0.1 MHz */ 239 | 240 | ifconf.enable = true; 241 | ifconf.rf_chain = 0; 242 | ifconf.freq_hz = 100000; 243 | ifconf.datarate = DR_LORA_MULTI; 244 | lgw_rxif_setconf(5, ifconf); /* chain 5: LoRa 125kHz, all SF, on f0 + 0.1 MHz */ 245 | 246 | ifconf.enable = true; 247 | ifconf.rf_chain = 1; 248 | ifconf.freq_hz = -100000; 249 | ifconf.datarate = DR_LORA_MULTI; 250 | lgw_rxif_setconf(6, ifconf); /* chain 6: LoRa 125kHz, all SF, on f1 - 0.1 MHz */ 251 | 252 | ifconf.enable = true; 253 | ifconf.rf_chain = 1; 254 | ifconf.freq_hz = 100000; 255 | ifconf.datarate = DR_LORA_MULTI; 256 | lgw_rxif_setconf(7, ifconf); /* chain 7: LoRa 125kHz, all SF, on f1 + 0.1 MHz */ 257 | 258 | /* set configuration for LoRa 'stand alone' channel */ 259 | memset(&ifconf, 0, sizeof(ifconf)); 260 | ifconf.enable = true; 261 | ifconf.rf_chain = 0; 262 | ifconf.freq_hz = 0; 263 | ifconf.bandwidth = BW_250KHZ; 264 | ifconf.datarate = DR_LORA_SF10; 265 | lgw_rxif_setconf(8, ifconf); /* chain 8: LoRa 250kHz, SF10, on f0 MHz */ 266 | 267 | /* set configuration for FSK channel */ 268 | memset(&ifconf, 0, sizeof(ifconf)); 269 | ifconf.enable = true; 270 | ifconf.rf_chain = 1; 271 | ifconf.freq_hz = 0; 272 | ifconf.bandwidth = BW_250KHZ; 273 | ifconf.datarate = 64000; 274 | lgw_rxif_setconf(9, ifconf); /* chain 9: FSK 64kbps, on f1 MHz */ 275 | 276 | /* set configuration for TX packet */ 277 | memset(&txpkt, 0, sizeof(txpkt)); 278 | txpkt.freq_hz = ft; 279 | txpkt.tx_mode = IMMEDIATE; 280 | txpkt.rf_power = 10; 281 | txpkt.modulation = MOD_LORA; 282 | txpkt.bandwidth = BW_250KHZ; 283 | txpkt.datarate = DR_LORA_SF10; 284 | txpkt.coderate = CR_LORA_4_5; 285 | strcpy((char *)txpkt.payload, "TX.TEST.LORA.GW.????" ); 286 | txpkt.size = 20; 287 | txpkt.preamble = 6; 288 | txpkt.rf_chain = 0; 289 | /* 290 | memset(&txpkt, 0, sizeof(txpkt)); 291 | txpkt.freq_hz = F_TX; 292 | txpkt.tx_mode = IMMEDIATE; 293 | txpkt.rf_power = 10; 294 | txpkt.modulation = MOD_FSK; 295 | txpkt.f_dev = 50; 296 | txpkt.datarate = 64000; 297 | strcpy((char *)txpkt.payload, "TX.TEST.LORA.GW.????" ); 298 | txpkt.size = 20; 299 | txpkt.preamble = 4; 300 | txpkt.rf_chain = 0; 301 | */ 302 | 303 | /* connect, configure and start the LoRa concentrator */ 304 | i = lgw_start(); 305 | if (i == LGW_HAL_SUCCESS) { 306 | printf("*** Concentrator started ***\n"); 307 | } else { 308 | printf("*** Impossible to start concentrator ***\n"); 309 | return -1; 310 | } 311 | 312 | /* once configured, dump content of registers to a file, for reference */ 313 | // FILE * reg_dump = NULL; 314 | // reg_dump = fopen("reg_dump.log", "w"); 315 | // if (reg_dump != NULL) { 316 | // lgw_reg_check(reg_dump); 317 | // fclose(reg_dump); 318 | // } 319 | 320 | while ((quit_sig != 1) && (exit_sig != 1)) { 321 | loop_cnt++; 322 | 323 | /* fetch N packets */ 324 | nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt); 325 | 326 | if (nb_pkt == 0) { 327 | wait_ms(300); 328 | } else { 329 | /* display received packets */ 330 | for(i=0; i < nb_pkt; ++i) { 331 | p = &rxpkt[i]; 332 | printf("---\nRcv pkt #%d >>", i+1); 333 | if (p->status == STAT_CRC_OK) { 334 | printf(" if_chain:%2d", p->if_chain); 335 | printf(" tstamp:%010u", p->count_us); 336 | printf(" size:%3u", p->size); 337 | switch (p-> modulation) { 338 | case MOD_LORA: printf(" LoRa"); break; 339 | case MOD_FSK: printf(" FSK"); break; 340 | default: printf(" modulation?"); 341 | } 342 | switch (p->datarate) { 343 | case DR_LORA_SF7: printf(" SF7"); break; 344 | case DR_LORA_SF8: printf(" SF8"); break; 345 | case DR_LORA_SF9: printf(" SF9"); break; 346 | case DR_LORA_SF10: printf(" SF10"); break; 347 | case DR_LORA_SF11: printf(" SF11"); break; 348 | case DR_LORA_SF12: printf(" SF12"); break; 349 | default: printf(" datarate?"); 350 | } 351 | switch (p->coderate) { 352 | case CR_LORA_4_5: printf(" CR1(4/5)"); break; 353 | case CR_LORA_4_6: printf(" CR2(2/3)"); break; 354 | case CR_LORA_4_7: printf(" CR3(4/7)"); break; 355 | case CR_LORA_4_8: printf(" CR4(1/2)"); break; 356 | default: printf(" coderate?"); 357 | } 358 | printf("\n"); 359 | printf(" RSSI:%+6.1f SNR:%+5.1f (min:%+5.1f, max:%+5.1f) payload:\n", p->rssi, p->snr, p->snr_min, p->snr_max); 360 | 361 | for (j = 0; j < p->size; ++j) { 362 | printf(" %02X", p->payload[j]); 363 | } 364 | printf(" #\n"); 365 | } else if (p->status == STAT_CRC_BAD) { 366 | printf(" if_chain:%2d", p->if_chain); 367 | printf(" tstamp:%010u", p->count_us); 368 | printf(" size:%3u\n", p->size); 369 | printf(" CRC error, damaged packet\n\n"); 370 | } else if (p->status == STAT_NO_CRC){ 371 | printf(" if_chain:%2d", p->if_chain); 372 | printf(" tstamp:%010u", p->count_us); 373 | printf(" size:%3u\n", p->size); 374 | printf(" no CRC\n\n"); 375 | } else { 376 | printf(" if_chain:%2d", p->if_chain); 377 | printf(" tstamp:%010u", p->count_us); 378 | printf(" size:%3u\n", p->size); 379 | printf(" invalid status ?!?\n\n"); 380 | } 381 | } 382 | } 383 | 384 | /* send a packet every X loop */ 385 | if (loop_cnt%16 == 0) { 386 | /* 32b counter in the payload, big endian */ 387 | txpkt.payload[16] = 0xff & (tx_cnt >> 24); 388 | txpkt.payload[17] = 0xff & (tx_cnt >> 16); 389 | txpkt.payload[18] = 0xff & (tx_cnt >> 8); 390 | txpkt.payload[19] = 0xff & tx_cnt; 391 | i = lgw_send(txpkt); /* non-blocking scheduling of TX packet */ 392 | j = 0; 393 | printf("+++\nSending packet #%d, rf path %d, return %d\nstatus -> ", tx_cnt, txpkt.rf_chain, i); 394 | do { 395 | ++j; 396 | wait_ms(100); 397 | lgw_status(TX_STATUS, &status_var); /* get TX status */ 398 | printf("%d:", status_var); 399 | } while ((status_var != TX_FREE) && (j < 100)); 400 | ++tx_cnt; 401 | printf("\nTX finished\n"); 402 | } 403 | } 404 | 405 | if (exit_sig == 1) { 406 | /* clean up before leaving */ 407 | lgw_stop(); 408 | } 409 | 410 | printf("\nEnd of test for loragw_hal.c\n"); 411 | return 0; 412 | } 413 | 414 | /* --- EOF ------------------------------------------------------------------ */ 415 | -------------------------------------------------------------------------------- /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 | 48 | for (i = 0; i < BURST_TEST_SIZE; ++i) { 49 | dataout[i] = 0x30 + (i % 10); /* ASCCI code for 0 -> 9 */ 50 | datain[i] = 0x23; /* garbage data, to be overwritten by received data */ 51 | } 52 | 53 | printf("Beginning of test for loragw_spi.c\n"); 54 | lgw_spi_open(&spi_target); 55 | 56 | /* normal R/W test */ 57 | for (i = 0; i < TIMING_REPEAT; ++i) 58 | lgw_spi_w(spi_target, 0xAA, 0x96); 59 | for (i = 0; i < TIMING_REPEAT; ++i) 60 | lgw_spi_r(spi_target, 0x55, &data); 61 | 62 | /* burst R/W test, small bursts << LGW_BURST_CHUNK */ 63 | for (i = 0; i < TIMING_REPEAT; ++i) 64 | lgw_spi_wb(spi_target, 0x55, dataout, 16); 65 | for (i = 0; i < TIMING_REPEAT; ++i) 66 | lgw_spi_rb(spi_target, 0x55, datain, 16); 67 | 68 | /* burst R/W test, large bursts >> LGW_BURST_CHUNK */ 69 | for (i = 0; i < TIMING_REPEAT; ++i) 70 | lgw_spi_wb(spi_target, 0x5A, dataout, ARRAY_SIZE(dataout)); 71 | for (i = 0; i < TIMING_REPEAT; ++i) 72 | lgw_spi_rb(spi_target, 0x5A, datain, ARRAY_SIZE(datain)); 73 | 74 | /* last read (blocking), just to be sure no to quit before the FTDI buffer is flushed */ 75 | lgw_spi_r(spi_target, 0x55, &data); 76 | printf("data received (simple read): %d\n",data); 77 | 78 | lgw_spi_close(spi_target); 79 | printf("End of test for loragw_spi.c\n"); 80 | 81 | return 0; 82 | } 83 | 84 | /* --- EOF ------------------------------------------------------------------ */ 85 | -------------------------------------------------------------------------------- /lora_card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirakonta/lora_gateway/0642acb11d56150f619d76f809fdfa48280df80e/lora_card.jpg -------------------------------------------------------------------------------- /mcard1.bmp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirakonta/lora_gateway/0642acb11d56150f619d76f809fdfa48280df80e/mcard1.bmp.jpg -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | #Attention 2 | This is a fork with the needed modifications to be able to use lora_gateway 3 | with a Multitech MTAC-LORA (MultiConnect mCard) board instead of a 4 | IoT Starter Kit platform. 5 | 6 | 7 | 8 | 9 | 10 | / _____) _ | | 11 | ( (____ _____ ____ _| |_ _____ ____| |__ 12 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 13 | _____) ) ____| | | || |_| ____( (___| | | | 14 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 15 | (C)2013 Semtech-Cycleo 16 | 17 | LoRa Gateway project 18 | ===================== 19 | 20 | 1. Core library: libloragw 21 | --------------------------- 22 | 23 | This directory contains the sources of the library to build a gateway based on 24 | a Semtech LoRa multi-channel RF receiver (a.k.a. concentrator). 25 | Once compiled all the code is contained in the libloragw.a file that will be 26 | statically linked (ie. integrated in the final executable). 27 | 28 | The library must be configured by editing the library.cfg file to set target 29 | platform, SPI interface, etc. 30 | 31 | The library also comes with a bunch of basic tests programs that are used to 32 | test the different sub-modules of the library. 33 | 34 | 2. Helper programs 35 | ------------------- 36 | 37 | Those programs are included in the project to provide examples on how to use 38 | the HAL library, and to help the system builder test different parts of it. 39 | 40 | ### 2.1. util_pkt_logger ### 41 | 42 | This software is used to set up a LoRa concentrator using a JSON configuration 43 | file and then record all the packets received in a log file, indefinitely, until 44 | the user stops the application. 45 | 46 | ### 2.2. util_spi_stress ### 47 | 48 | This software is used to check the reliability of the link between the host 49 | platform (on which the program is run) and the LoRa concentrator register file 50 | that is the interface through which all interaction with the LoRa concentrator 51 | happens. 52 | 53 | ### 2.3. util_tx_test ### 54 | 55 | This software is used to send test packets with a LoRa concentrator. The packets 56 | contain little information, on no protocol (ie. MAC address) information but 57 | can be used to assess the functionality of a gateway downlink using other 58 | gateways as receivers. 59 | 60 | ### 2.4. util_tx_continuous ### 61 | 62 | This software is used to set LoRa concentrator in Tx continuous mode, 63 | for spectral measurement. 64 | 65 | 3. Changelog 66 | ------------- 67 | 68 | ### v3.1.0 ### 69 | 70 | * Removed GPIO module from HAL, that was specific to IoT Starter Kit platform. GPIO configuration will be done from application script instead. 71 | * Removed CFG_BRD configuration from library.cfg, not needed anymore 72 | 73 | ### v3.0.2 ### 74 | 75 | * Bugfix: Fixed frequency calculation on uplinks: lgw_receive() function was using a variable to calculate the frequency before it was initialized with correct value. 76 | * Bugfix: util_pkt_logger crashed when no gateway_ID is not defined in global_conf.json 77 | 78 | ### v3.0.1 ### 79 | 80 | * Bufgix: Fixed util_tx_continuous compilation issue, by adding empty obj directory 81 | * Bugfix: Fixed HAL compilation issue for CFG_SPI=ftdi, removed dependency on loragw_gpio in this case 82 | 83 | ### v3.0.0 ### 84 | 85 | * Added new HAL function lgw_board_setconf() to configure board/concentrator specific parameters: network type (LoRa public or private), concentrator clock source. Note: those parameters are not any more set from the library.cfg file configuration (CFG_NET, CFG_BRD), and should be passed at initialization by the application. 86 | * Added new HAL function lgw_txgain_setconf() to configure concentrator TX gain table. It can now be dynamically set by the application at initialization time. 87 | * Changed HAL function lgw_rxrf_setconf(), it will now also configure the radio type (CFG_RADIO has been removed from library.cfg), the RSSI offset to be used for this radio and if TX is enabled or not on this radio. 88 | * Added support of IoT Starter Kit platform, which is now the default board. 89 | * Added util_tx_continuous utility for gateway TX power calibration and spectral emission measurements/qualification. 90 | * Removed CFG_BAND configuration from library.cfg. Band configuration is done by application and passed dynamically at initialization time. 91 | * Updated makefiles to allow cross compilation from environment variable (ARCH, CROSS_COMPILE). 92 | 93 | ** WARNING: ** 94 | ** Known issue: a problem with carrier leakage calibration has been seen on 433MHz boards. ** 95 | 96 | ### v2.0.0 ### 97 | 98 | * Added support for Kerlink 868 27dBm gateway 99 | * Updated global_conf.eu868.json (in packet logger) to new LoRaWAN frequency plan 100 | * Added version numbers to AGC, arbiter and calibration firmware (those versions are checked at startup) 101 | * Added test_loragw_cal to test radio calibrations 102 | * Fixed minor bug in error coverage in register read/write functions 103 | 104 | /!\ warning: Kerlink 868 27dBm gateway includes a FPGA that MUST be programmed before running any application 105 | 106 | ### v1.7.0 ### 107 | 108 | * Added TX “start delay” compensation for timestamp mode (fix time window alignment issue at low SF and/or high BW) 109 | * Added adaptive narrowband/wideband TX filtering for LoRa 110 | * Added a command-line option to set CR in util_tx_test 111 | * Added notes for TX “start delay” in immediate and triggered mode 112 | 113 | /!\ warning: due to start delay compensation being implemented, TX that were 114 | previously 1.5ms late will be sent on time. At low datarate, this is not an 115 | issue. At high LoRa data rate (and FSK) you might have to adjust your timing. 116 | 117 | ### v1.6.0 ### 118 | 119 | * Fixed bug with 250kHz and 500 kHz TX filtering 120 | * Adjusted FSK timestamp calibration in RX for accurate RX/TX alignment 121 | * Added lgw_abort_tx() function to stop a TX at any time (scheduled or ongoing) 122 | * Added support for user-settable FSK sync word (same for RX and TX) 123 | * Added support for the Chinese 780 MHz band 124 | * Added support for Kerlink 433 gateway 125 | * Added support for Cisco 433, 470 & 780 MHz concentrators boards 126 | 127 | ### v1.5.0 ### 128 | 129 | * Adding option to isolate public LoRa MAC networks at PHY level. 130 | 131 | ### v1.4.1 ### 132 | 133 | * Enabling support for FSK per LoRa MAC specification 134 | * Adjusting TX and RX calibration set on 868 reference board 135 | * Added specific RX/TX calibration set for Kerlink 868 "IoT station" gateway 136 | * Changed default SPI port for native driver to Kerlink SPI device number 137 | 138 | ### v1.4.0 ### 139 | 140 | * Added calibration routine to optimize RF performance 141 | * Added support for SX1301 433 MHz reference board 142 | * Improved AGC firmware 143 | * Improved RSSI accuracy 144 | * Improved utilities Makefile 145 | 146 | ### v1.3.0 ### 147 | 148 | * Added TX power management. 149 | * Added full support for SX1301 reference board. 150 | * Changed build system with configuration for multiple chip/radio/band support. 151 | * SX125x bandwidth set to 1MHz by default (was 800 kHz). 152 | * Solved warnings with 64b integer printf when compiling on x86_64. 153 | * Renamed helper programs to reduce the concentrator vs. gateway confusion. 154 | 155 | ### v1.2.2 ### 156 | 157 | * Added a GPIO toggle on the FTDI SPI module to reset the SX1301 board. 158 | 159 | ### v1.2.1 ### 160 | 161 | * Fixed 'floating point exception' crash when concentrator returned a packet with SF=0 (CRC error on LoRa header). 162 | * Fixed buggy timezone handling. 163 | 164 | ### v1.2.0 ### 165 | 166 | * Added feature: new GPS module in the library for synchronization. 167 | * Removed feature: no more missed deadline detection in TX because of incompatibility with GPS. 168 | * Added documentation for GPS and legal notice. 169 | * Added flags in Makefiles for easier cross-compilation. 170 | 171 | ### v1.1.0 ### 172 | 173 | * Fixed bug 'no TX on radio B' (rfch 1). 174 | * Added feature: concentrator processing delay compensation in the receive() function for accurate 'end of packet' even timestamping. 175 | * Added feature: TX 'start delay' compensation in the send() function to emit packet exactly on target timestamp. 176 | * Added feature: timestamp counter verification in send() function, return an error if scheduling was too late. 177 | * Switched license to 'Revised BSD'. 178 | 179 | ### v1.0.0 (from beta 8) ### 180 | 181 | * Switched FTDI as default SPI phy layer in library.cfg. 182 | * Fixed a bug in TX power control; still only two TW power available, 14 and 24 dBm. 183 | * Changed library directory name from loragw_hal to libloragw to follow usual conventions. 184 | 185 | ### Beta 8 (from beta 7) ### 186 | 187 | * API: lgw_receive now return info on RX frequency and RF path for each packet (no need to keep track of RF/IF settings). 188 | * Unified some portion of the code with the 470 MHz variant of the HAL (use SX1255 radios instead of SX1257). 189 | * Improved AGC and ARB firmwares. 190 | * Adding -Wall -Wextra for compilation, fixing all the new warnings for cleaner code. 191 | * Fixed bugs in handling of FSK datarate. 192 | * test_loragw_hal now dumps the content of all LoRa registers after configuration in reg_dump.log. 193 | 194 | ### Beta 7 (from beta 5) ### 195 | 196 | * Reduced number of SPI transactions to fetch a packet (improved number a packets par second that can be downloaded from concentrator). 197 | * Streamlined build process, main target is now a static library: libloragw.a. 198 | * Change memory allocation for payload: they are now part of the struct for TX/RX, no need to malloc/free. 199 | * All RX chains can use any of the two radios now. 200 | * FSK is available and working in TX and RX (variable length mode). 201 | * Calibrated RSSI for FSK. 202 | * lgw_connect now check the CHIP_ID. 203 | * Added a license file and a changelog. 204 | * Added a function returning a version string to allow identification of the version/options once compiled. 205 | 206 | ### Beta 6 ### 207 | 208 | Private release, not taken into account in that changelog. 209 | 210 | ### Beta 5 (from beta 4) ### 211 | 212 | * Updated registers, firmware and configuration to align with r986 bitstream revision. 213 | * Calibrated RSSI for LoRa "multi" and LoRa "stand alone" modems. 214 | * Renamed some confusing TX status code. 215 | * Added preliminary FSK support. 216 | 217 | ### Beta 4 (from beta 3) ### 218 | 219 | * Unified build environment with selectable SPI layer (Linux native or FTDI SPI-over-USB bridge). 220 | * Remove the 500 kHz limit on radio bandwith, back to the nominal 800 kHz. 221 | * Renamed debug flags. 222 | 223 | 4. Legal notice 224 | ---------------- 225 | 226 | The information presented in this project documentation does not form part of 227 | any quotation or contract, is believed to be accurate and reliable and may be 228 | changed without notice. No liability will be accepted by the publisher for any 229 | consequence of its use. Publication thereof does not convey nor imply any 230 | license under patent or other industrial or intellectual property rights. 231 | Semtech assumes no responsibility or liability whatsoever for any failure or 232 | unexpected operation resulting from misuse, neglect improper installation, 233 | repair or improper handling or unusual physical or electrical stress 234 | including, but not limited to, exposure to parameters beyond the specified 235 | maximum ratings or operation outside the specified range. 236 | 237 | SEMTECH PRODUCTS ARE NOT DESIGNED, INTENDED, AUTHORIZED OR WARRANTED TO BE 238 | SUITABLE FOR USE IN LIFE-SUPPORT APPLICATIONS, DEVICES OR SYSTEMS OR OTHER 239 | CRITICAL APPLICATIONS. INCLUSION OF SEMTECH PRODUCTS IN SUCH APPLICATIONS IS 240 | UNDERSTOOD TO BE UNDERTAKEN SOLELY AT THE CUSTOMER’S OWN RISK. Should a 241 | customer purchase or use Semtech products for any such unauthorized 242 | application, the customer shall indemnify and hold Semtech and its officers, 243 | employees, subsidiaries, affiliates, and distributors harmless against all 244 | claims, costs damages and attorney fees which could arise. 245 | 246 | *EOF* 247 | -------------------------------------------------------------------------------- /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 | # 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 | ### Constants for LoRa concentrator HAL library 24 | # List the library sub-modules that are used by the application 25 | 26 | LGW_INC = $(LGW_PATH)/inc/config.h 27 | LGW_INC += $(LGW_PATH)/inc/loragw_hal.h 28 | 29 | ### Linking options 30 | 31 | ifeq ($(CFG_SPI),native) 32 | LIBS := -lloragw -lrt 33 | else ifeq ($(CFG_SPI),ftdi) 34 | LIBS := -lloragw -lrt -lmpsse 35 | endif 36 | 37 | ### General build targets 38 | 39 | all: $(APP_NAME) 40 | 41 | clean: 42 | rm -f obj/*.o 43 | rm -f $(APP_NAME) 44 | 45 | ### HAL library (do no force multiple library rebuild even with 'make -B') 46 | 47 | $(LGW_PATH)/inc/config.h: 48 | @if test ! -f $@; then \ 49 | $(MAKE) all -C $(LGW_PATH); \ 50 | fi 51 | 52 | $(LGW_PATH)/libloragw.a: $(LGW_INC) 53 | @if test ! -f $@; then \ 54 | $(MAKE) all -C $(LGW_PATH); \ 55 | fi 56 | 57 | ### Sub-modules compilation 58 | 59 | obj/parson.o: src/parson.c inc/parson.h 60 | $(CC) -c $(CFLAGS) $< -o $@ 61 | 62 | ### Main program compilation and assembly 63 | 64 | obj/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) inc/parson.h 65 | $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@ 66 | 67 | $(APP_NAME): obj/$(APP_NAME).o $(LGW_PATH)/libloragw.a obj/parson.o 68 | $(CC) -L$(LGW_PATH) $< obj/parson.o -o $@ $(LIBS) 69 | 70 | ### EOF 71 | -------------------------------------------------------------------------------- /util_pkt_logger/global_conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "SX1301_conf": { 3 | "lorawan_public": true, 4 | "clksrc": 0, /* radio_0 provides clock to concentrator */ 5 | "radio_0": { 6 | "enable": true, 7 | "type": "SX1257", 8 | "freq": 868200000, 9 | "rssi_offset": -166.0, 10 | "tx_enable": true 11 | }, 12 | "radio_1": { 13 | "enable": true, 14 | "type": "SX1257", 15 | "freq": 869200000, 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": 0, 23 | "if": -100000 24 | }, 25 | "chan_multiSF_1": { 26 | /* Lora MAC channel, 125kHz, all SF, 868.3 MHz */ 27 | "enable": true, 28 | "radio": 0, 29 | "if": 100000 30 | }, 31 | "chan_multiSF_2": { 32 | /* Lora MAC channel, 125kHz, all SF, 868.5 MHz */ 33 | "enable": true, 34 | "radio": 0, 35 | "if": 300000 36 | }, 37 | "chan_multiSF_3": { 38 | /* Lora MAC channel, 125kHz, all SF, 868.85 MHz */ 39 | "enable": true, 40 | "radio": 1, 41 | "if": -350000 42 | }, 43 | "chan_multiSF_4": { 44 | /* Lora MAC channel, 125kHz, all SF, 869.05 MHz */ 45 | "enable": true, 46 | "radio": 1, 47 | "if": -150000 48 | }, 49 | "chan_multiSF_5": { 50 | /* Lora MAC channel, 125kHz, all SF, 869.525 MHz */ 51 | "enable": true, 52 | "radio": 1, 53 | "if": 325000 54 | }, 55 | "chan_multiSF_6": { 56 | "enable": false, 57 | "radio": 0, 58 | "if": 0 59 | }, 60 | "chan_multiSF_7": { 61 | "enable": false, 62 | "radio": 0, 63 | "if": 0 64 | }, 65 | "chan_Lora_std": { 66 | /* Lora MAC channel, 250kHz, SF7, 868.3 MHz */ 67 | "enable": true, 68 | "radio": 0, 69 | "if": 100000, 70 | "bandwidth": 250000, 71 | "spread_factor": 7 72 | }, 73 | "chan_FSK": { 74 | /* FSK 50kbps channel, 868.3 MHz */ 75 | "enable": true, 76 | "radio": 0, 77 | "if": 100000, 78 | "bandwidth": 125000, 79 | "datarate": 50000 80 | }, 81 | "tx_lut_0": { 82 | /* TX gain table, index 0 */ 83 | "pa_gain": 0, 84 | "mix_gain": 8, 85 | "rf_power": -6, 86 | "dig_gain": 0 87 | }, 88 | "tx_lut_1": { 89 | /* TX gain table, index 1 */ 90 | "pa_gain": 0, 91 | "mix_gain": 10, 92 | "rf_power": -3, 93 | "dig_gain": 0 94 | }, 95 | "tx_lut_2": { 96 | /* TX gain table, index 2 */ 97 | "pa_gain": 0, 98 | "mix_gain": 12, 99 | "rf_power": 0, 100 | "dig_gain": 0 101 | }, 102 | "tx_lut_3": { 103 | /* TX gain table, index 3 */ 104 | "pa_gain": 1, 105 | "mix_gain": 8, 106 | "rf_power": 3, 107 | "dig_gain": 0 108 | }, 109 | "tx_lut_4": { 110 | /* TX gain table, index 4 */ 111 | "pa_gain": 1, 112 | "mix_gain": 10, 113 | "rf_power": 6, 114 | "dig_gain": 0 115 | }, 116 | "tx_lut_5": { 117 | /* TX gain table, index 5 */ 118 | "pa_gain": 1, 119 | "mix_gain": 12, 120 | "rf_power": 10, 121 | "dig_gain": 0 122 | }, 123 | "tx_lut_6": { 124 | /* TX gain table, index 6 */ 125 | "pa_gain": 1, 126 | "mix_gain": 13, 127 | "rf_power": 11, 128 | "dig_gain": 0 129 | }, 130 | "tx_lut_7": { 131 | /* TX gain table, index 7 */ 132 | "pa_gain": 2, 133 | "mix_gain": 9, 134 | "rf_power": 12, 135 | "dig_gain": 0 136 | }, 137 | "tx_lut_8": { 138 | /* TX gain table, index 8 */ 139 | "pa_gain": 1, 140 | "mix_gain": 15, 141 | "rf_power": 13, 142 | "dig_gain": 0 143 | }, 144 | "tx_lut_9": { 145 | /* TX gain table, index 9 */ 146 | "pa_gain": 2, 147 | "mix_gain": 10, 148 | "rf_power": 14, 149 | "dig_gain": 0 150 | }, 151 | "tx_lut_10": { 152 | /* TX gain table, index 10 */ 153 | "pa_gain": 2, 154 | "mix_gain": 11, 155 | "rf_power": 16, 156 | "dig_gain": 0 157 | }, 158 | "tx_lut_11": { 159 | /* TX gain table, index 11 */ 160 | "pa_gain": 3, 161 | "mix_gain": 10, 162 | "rf_power": 20, 163 | "dig_gain": 0 164 | }, 165 | "tx_lut_12": { 166 | /* TX gain table, index 12 */ 167 | "pa_gain": 3, 168 | "mix_gain": 11, 169 | "rf_power": 23, 170 | "dig_gain": 0 171 | }, 172 | "tx_lut_13": { 173 | /* TX gain table, index 13 */ 174 | "pa_gain": 3, 175 | "mix_gain": 12, 176 | "rf_power": 24, 177 | "dig_gain": 0 178 | }, 179 | "tx_lut_14": { 180 | /* TX gain table, index 14 */ 181 | "pa_gain": 3, 182 | "mix_gain": 13, 183 | "rf_power": 25, 184 | "dig_gain": 0 185 | }, 186 | "tx_lut_15": { 187 | /* TX gain table, index 15 */ 188 | "pa_gain": 3, 189 | "mix_gain": 15, 190 | "rf_power": 26, 191 | "dig_gain": 0 192 | } 193 | }, 194 | "gateway_conf": { 195 | "gateway_ID": "AA555A0000000000" 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /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/obj/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirakonta/lora_gateway/0642acb11d56150f619d76f809fdfa48280df80e/util_pkt_logger/obj/.gitkeep -------------------------------------------------------------------------------- /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_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 | ### Constants for LoRa concentrator HAL library 24 | # List the library sub-modules that are used by the application 25 | 26 | LGW_INC = $(LGW_PATH)/inc/config.h 27 | LGW_INC += $(LGW_PATH)/inc/loragw_reg.h 28 | 29 | ### Linking options 30 | 31 | ifeq ($(CFG_SPI),native) 32 | LIBS := -lloragw -lrt 33 | else ifeq ($(CFG_SPI),ftdi) 34 | LIBS := -lloragw -lrt -lmpsse 35 | endif 36 | 37 | ### General build targets 38 | 39 | all: $(APP_NAME) 40 | 41 | clean: 42 | rm -f obj/*.o 43 | rm -f $(APP_NAME) 44 | 45 | ### HAL library (do no force multiple library rebuild even with 'make -B') 46 | 47 | $(LGW_PATH)/inc/config.h: 48 | @if test ! -f $@; then \ 49 | $(MAKE) all -C $(LGW_PATH); \ 50 | fi 51 | 52 | $(LGW_PATH)/libloragw.a: $(LGW_INC) 53 | @if test ! -f $@; then \ 54 | $(MAKE) all -C $(LGW_PATH); \ 55 | fi 56 | 57 | ### Main program compilation and assembly 58 | 59 | obj/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) 60 | $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@ 61 | 62 | $(APP_NAME): obj/$(APP_NAME).o $(LGW_PATH)/libloragw.a 63 | $(CC) -L$(LGW_PATH) $< -o $@ $(LIBS) 64 | 65 | ### EOF 66 | -------------------------------------------------------------------------------- /util_spi_stress/obj/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirakonta/lora_gateway/0642acb11d56150f619d76f809fdfa48280df80e/util_spi_stress/obj/.gitkeep -------------------------------------------------------------------------------- /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 | #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 fprintf sprintf fopen fputs */ 30 | 31 | #include /* sigaction */ 32 | #include /* getopt access */ 33 | #include /* rand */ 34 | 35 | #include "loragw_reg.h" 36 | 37 | /* -------------------------------------------------------------------------- */ 38 | /* --- PRIVATE MACROS ------------------------------------------------------- */ 39 | 40 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 41 | #define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */ 42 | 43 | /* -------------------------------------------------------------------------- */ 44 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ 45 | 46 | #define VERS 103 47 | #define READS_WHEN_ERROR 16 /* number of times a read is repeated if there is a read error */ 48 | #define BUFF_SIZE 1024 49 | 50 | /* -------------------------------------------------------------------------- */ 51 | /* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ 52 | 53 | /* signal handling variables */ 54 | struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ 55 | static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ 56 | static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */ 57 | 58 | /* -------------------------------------------------------------------------- */ 59 | /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ 60 | 61 | static void sig_handler(int sigio); 62 | 63 | void usage (void); 64 | 65 | /* -------------------------------------------------------------------------- */ 66 | /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ 67 | 68 | static void sig_handler(int sigio) { 69 | if (sigio == SIGQUIT) { 70 | quit_sig = 1;; 71 | } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { 72 | exit_sig = 1; 73 | } 74 | } 75 | 76 | /* describe command line options */ 77 | void usage(void) { 78 | MSG( "Available options:\n"); 79 | MSG( " -h print this help\n"); 80 | MSG( " -t specify which test you want to run (1-4)\n"); 81 | } 82 | 83 | /* -------------------------------------------------------------------------- */ 84 | /* --- MAIN FUNCTION -------------------------------------------------------- */ 85 | 86 | int main(int argc, char **argv) 87 | { 88 | int i; 89 | int xi = 0; 90 | 91 | /* application option */ 92 | int test_number = 1; 93 | int cycle_number = 0; 94 | int repeats_per_cycle = 1000; 95 | bool error = false; 96 | 97 | /* in/out variables */ 98 | int32_t test_value; 99 | int32_t read_value; 100 | int32_t rb1, rb2, rb3; /* interstitial readbacks, to flush buffers if needed */ 101 | 102 | /* data buffer */ 103 | int32_t test_addr; 104 | uint8_t test_buff[BUFF_SIZE]; 105 | uint8_t read_buff[BUFF_SIZE]; 106 | 107 | /* parse command line options */ 108 | while ((i = getopt (argc, argv, "ht:")) != -1) { 109 | switch (i) { 110 | case 'h': 111 | usage(); 112 | return EXIT_FAILURE; 113 | break; 114 | 115 | case 't': 116 | i = sscanf(optarg, "%i", &xi); 117 | if ((i != 1) || (xi < 1) || (xi > 4)) { 118 | MSG("ERROR: invalid test number\n"); 119 | return EXIT_FAILURE; 120 | } else { 121 | test_number = xi; 122 | } 123 | break; 124 | 125 | default: 126 | MSG("ERROR: argument parsing use -h option for help\n"); 127 | usage(); 128 | return EXIT_FAILURE; 129 | } 130 | } 131 | MSG("INFO: Starting LoRa concentrator SPI stress-test number %i\n", test_number); 132 | 133 | /* configure signal handling */ 134 | sigemptyset(&sigact.sa_mask); 135 | sigact.sa_flags = 0; 136 | sigact.sa_handler = sig_handler; 137 | sigaction(SIGQUIT, &sigact, NULL); 138 | sigaction(SIGINT, &sigact, NULL); 139 | sigaction(SIGTERM, &sigact, NULL); 140 | 141 | /* start SPI link */ 142 | i = lgw_connect(); 143 | if (i != LGW_REG_SUCCESS) { 144 | MSG("ERROR: lgw_connect() did not return SUCCESS"); 145 | return EXIT_FAILURE; 146 | } 147 | 148 | if (test_number == 1) { 149 | /* single 8b register R/W stress test */ 150 | while ((quit_sig != 1) && (exit_sig != 1)) { 151 | printf("Cycle %i > ", cycle_number); 152 | for (i=0; i ", cycle_number); 179 | for (i=0; i ", cycle_number); 209 | for (i=0; i ", cycle_number); 240 | test_addr = rand() & 0xFFFF; 241 | lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* write at random offset in memory */ 242 | lgw_reg_wb(LGW_RX_DATA_BUF_DATA, test_buff, BUFF_SIZE); 243 | lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* go back to start of segment */ 244 | lgw_reg_rb(LGW_RX_DATA_BUF_DATA, read_buff, BUFF_SIZE); 245 | for (i=0; ((i= 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 | #include /* memset */ 32 | #include /* sigaction */ 33 | #include /* getopt access */ 34 | #include /* exit codes */ 35 | #include /* getopt_long */ 36 | 37 | #include "loragw_hal.h" 38 | #include "loragw_reg.h" 39 | #include "loragw_aux.h" 40 | 41 | /* -------------------------------------------------------------------------- */ 42 | /* --- MACROS & CONSTANTS --------------------------------------------------- */ 43 | 44 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 45 | 46 | #define SX125x_VERSION 0x21 47 | #define SX125x_32MHz_FRAC 15625 /* irreductible fraction for PLL register caculation */ 48 | #define SX125x_TX_DAC_CLK_SEL 1 /* 0:int, 1:ext */ 49 | #define SX125x_TX_DAC_GAIN 2 /* 3:0, 2:-3, 1:-6, 0:-9 dBFS (default 2) */ 50 | #define SX125x_TX_MIX_GAIN 14 /* -38 + 2*TxMixGain dB (default 14) */ 51 | #define SX125x_TX_PLL_BW 3 /* 0:75, 1:150, 2:225, 3:300 kHz (default 3) */ 52 | #define SX125x_TX_ANA_BW 0 /* 17.5 / 2*(41-TxAnaBw) MHz (default 0) */ 53 | #define SX125x_TX_DAC_BW 5 /* 24 + 8*TxDacBw Nb FIR taps (default 2) */ 54 | #define SX125x_XOSC_GM_STARTUP 13 /* (default 13) */ 55 | #define SX125x_XOSC_DISABLE 2 /* Disable of Xtal Oscillator blocks bit0:regulator, bit1:core(gm), bit2:amplifier */ 56 | 57 | #define DEFAULT_FREQ_HZ 868e6 58 | #define DEFAULT_RADIO 0 59 | #define DEFAULT_DIGITAL_GAIN 0 60 | #define DEFAULT_DAC_GAIN 3 61 | #define DEFAULT_MIXER_GAIN 14 62 | #define DEFAULT_PA_VOLTAGE 1.5 63 | #define DEFAULT_MODULATION "LORA" 64 | #define DEFAULT_SF 7 65 | #define DEFAULT_BW_KHZ 125 66 | #define DEFAULT_BR_KBPS 50 67 | #define DEFAULT_FDEV_KHZ 25 68 | #define DEFAULT_BT 2 69 | 70 | /* -------------------------------------------------------------------------- */ 71 | /* --- GLOBAL VARIABLES ----------------------------------------------------- */ 72 | 73 | /* Signal handling variables */ 74 | static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ 75 | static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */ 76 | 77 | #include "cal_tx_fw.var" 78 | #include "util_fw.var" 79 | 80 | /* -------------------------------------------------------------------------- */ 81 | /* --- SUBFUNCTIONS DECLARATION --------------------------------------------- */ 82 | 83 | static void sig_handler(int sigio); 84 | 85 | void sx125x_write(uint8_t channel, uint8_t addr, uint8_t data); /* defined in loragw_hal.c */ 86 | 87 | uint8_t sx125x_read(uint8_t channel, uint8_t addr); /* defined in loragw_hal.c */ 88 | 89 | int load_firmware(uint8_t target, uint8_t *firmware, uint16_t size); /* defined in loragw_hal.c */ 90 | 91 | /* -------------------------------------------------------------------------- */ 92 | /* --- MAIN FUNCTION -------------------------------------------------------- */ 93 | 94 | int main(int argc, char **argv) 95 | { 96 | static struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ 97 | 98 | int i; /* loop and temporary variables */ 99 | int x; /* return code for HAL functions */ 100 | 101 | /* Parameter parsing */ 102 | int option_index = 0; 103 | static struct option long_options[] = { 104 | {"dig", 1, 0, 0}, 105 | {"dac", 1, 0, 0}, 106 | {"mix", 1, 0, 0}, 107 | {"pa", 1, 0, 0}, 108 | {"mod", 1, 0, 0}, 109 | {"sf", 1, 0, 0}, 110 | {"bw", 1, 0, 0}, 111 | {"br", 1, 0, 0}, 112 | {"fdev", 1, 0, 0}, 113 | {"bt", 1, 0, 0}, 114 | {0, 0, 0, 0} 115 | }; 116 | unsigned int arg_u; 117 | float arg_f; 118 | char arg_s[64]; 119 | 120 | /* Application parameters */ 121 | uint32_t freq_hz = DEFAULT_FREQ_HZ; 122 | bool radio_select = DEFAULT_RADIO; 123 | uint8_t g_dig = DEFAULT_DIGITAL_GAIN; 124 | uint8_t g_dac = DEFAULT_DAC_GAIN; 125 | uint8_t g_mix = DEFAULT_MIXER_GAIN; 126 | uint8_t g_pa = DEFAULT_PA_VOLTAGE; 127 | char mod[64] = DEFAULT_MODULATION; 128 | uint8_t sf = DEFAULT_SF; 129 | unsigned int bw_khz = DEFAULT_BW_KHZ; 130 | float br_kbps = DEFAULT_BR_KBPS; 131 | uint8_t fdev_khz = DEFAULT_FDEV_KHZ; 132 | uint8_t bt = DEFAULT_BT; 133 | 134 | uint8_t buff[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 135 | uint32_t part_int; /* integer part for PLL register value calculation */ 136 | uint32_t part_frac; /* fractional part for PLL register value calculation */ 137 | uint16_t br; 138 | int32_t offset_i, offset_q; 139 | bool is_sx1255; 140 | int32_t cal_status, cal_status_expected; 141 | int32_t tx_status; 142 | 143 | /* Parse command line options */ 144 | while( (i = getopt_long (argc, argv, "hud::f:r:", long_options, &option_index)) != -1 ) 145 | { 146 | switch( i ) 147 | { 148 | case 'h': 149 | printf( "~~~ Library version string~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" ); 150 | printf( " %s\n", lgw_version_info( ) ); 151 | printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" ); 152 | printf( " -f Tx RF frequency in MHz [800:1000]\n"); 153 | printf( " -r Radio select, 0:A 1:B\n"); 154 | printf( " --dig Digital gain trim, [0:3]\n" ); 155 | printf( " 0:1, 1:7/8, 2:3/4, 3:1/2\n" ); 156 | printf( " --mix SX1257 Tx mixer gain trim, [0:15]\n" ); 157 | printf( " 15 corresponds to maximum gain, 1 LSB corresponds to 2dB step\n" ); 158 | printf( " --pa PA gain trim, [0:3]\n" ); 159 | printf( " --mod Modulation type ['LORA','FSK','CW']\n" ); 160 | printf( " --sf LoRa Spreading Factor, [7:12]\n" ); 161 | printf( " --bw LoRa bandwidth in kHz, [125,250,500]\n" ); 162 | printf( " --br FSK bitrate in kbps, [0.5:250]\n" ); 163 | printf( " --fdev FSK frequency deviation in kHz, [1:250]\n" ); 164 | printf( " --bt FSK gaussian filter BT trim, [0:3]\n" ); 165 | printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" ); 166 | return EXIT_SUCCESS; 167 | break; 168 | 169 | case 0: 170 | if( strcmp(long_options[option_index].name,"dig") == 0 ) 171 | { 172 | i = sscanf(optarg, "%u", &arg_u); 173 | if( (i != 1) || (arg_u > 3) ) 174 | { 175 | printf( "ERROR: argument parsing of --dig argument. Use -h to print help\n" ); 176 | return EXIT_FAILURE; 177 | } 178 | else 179 | { 180 | g_dig = (uint8_t)arg_u; 181 | } 182 | } 183 | else if( strcmp(long_options[option_index].name,"dac") == 0 ) 184 | { 185 | i = sscanf(optarg, "%u", &arg_u); 186 | if( (i != 1) || (arg_u > 3) ) 187 | { 188 | printf( "ERROR: argument parsing of --dac argument. Use -h to print help\n" ); 189 | return EXIT_FAILURE; 190 | } 191 | else 192 | { 193 | g_dac = (uint8_t)arg_u; 194 | } 195 | } 196 | else if( strcmp(long_options[option_index].name,"mix") == 0 ) 197 | { 198 | i = sscanf(optarg, "%u", &arg_u); 199 | if( (i != 1) || (arg_u > 15) ) 200 | { 201 | printf( "ERROR: argument parsing of --mix argument. Use -h to print help\n" ); 202 | return EXIT_FAILURE; 203 | } 204 | else 205 | { 206 | g_mix = (uint8_t)arg_u; 207 | } 208 | } 209 | else if( strcmp(long_options[option_index].name,"pa") == 0 ) 210 | { 211 | i = sscanf(optarg, "%u", &arg_u); 212 | if( (i != 1) || (arg_u > 3) ) 213 | { 214 | printf( "ERROR: argument parsing of --pa argument. Use -h to print help\n" ); 215 | return EXIT_FAILURE; 216 | } 217 | else 218 | { 219 | g_pa = arg_u; 220 | } 221 | } 222 | else if( strcmp(long_options[option_index].name,"mod") == 0 ) 223 | { 224 | i = sscanf(optarg, "%s", arg_s); 225 | if( (i != 1) || ((strcmp(arg_s,"LORA") != 0) && (strcmp(arg_s,"FSK") != 0) && (strcmp(arg_s,"CW") != 0)) ) 226 | { 227 | printf( "ERROR: argument parsing of --mod argument. Use -h to print help\n" ); 228 | return EXIT_FAILURE; 229 | } 230 | else 231 | { 232 | sprintf(mod, "%s", arg_s); 233 | } 234 | } 235 | else if( strcmp(long_options[option_index].name,"sf") == 0 ) 236 | { 237 | i = sscanf(optarg, "%u", &arg_u); 238 | if( (i != 1) || (arg_u < 7) || (arg_u > 12) ) 239 | { 240 | printf( "ERROR: argument parsing of --sf argument. Use -h to print help\n" ); 241 | return EXIT_FAILURE; 242 | } 243 | else 244 | { 245 | sf = (uint8_t)arg_u; 246 | } 247 | } 248 | else if( strcmp(long_options[option_index].name,"bw") == 0 ) 249 | { 250 | i = sscanf(optarg, "%u", &arg_u); 251 | if( (i != 1) || ((arg_u != 125) && (arg_u != 250) && (arg_u != 500)) ) 252 | { 253 | printf( "ERROR: argument parsing of --bw argument. Use -h to print help\n" ); 254 | return EXIT_FAILURE; 255 | } 256 | else 257 | { 258 | bw_khz = arg_u; 259 | } 260 | } 261 | else if( strcmp(long_options[option_index].name,"br") == 0 ) 262 | { 263 | i = sscanf(optarg, "%f", &arg_f); 264 | if( (i != 1) || (arg_f < 0.5) || (arg_f > 250) ) 265 | { 266 | printf( "ERROR: argument parsing of --br argument. Use -h to print help\n" ); 267 | return EXIT_FAILURE; 268 | } 269 | else 270 | { 271 | br_kbps = arg_f; 272 | } 273 | } 274 | else if( strcmp(long_options[option_index].name,"fdev") == 0 ) 275 | { 276 | i = sscanf(optarg, "%u", &arg_u); 277 | if( (i != 1) || (arg_u < 1) || (arg_u > 250) ) 278 | { 279 | printf( "ERROR: argument parsing of --fdev argument. Use -h to print help\n" ); 280 | return EXIT_FAILURE; 281 | } 282 | else 283 | { 284 | fdev_khz = (uint8_t)arg_u; 285 | } 286 | } 287 | else if( strcmp(long_options[option_index].name,"bt") == 0 ) 288 | { 289 | i = sscanf(optarg, "%u", &arg_u); 290 | if( (i != 1) || (arg_u > 3) ) 291 | { 292 | printf( "ERROR: argument parsing of --bt argument. Use -h to print help\n" ); 293 | return EXIT_FAILURE; 294 | } 295 | else 296 | { 297 | bt = (uint8_t)arg_u; 298 | } 299 | } 300 | else { 301 | printf( "ERROR: argument parsing options. Use -h to print help\n" ); 302 | return EXIT_FAILURE; 303 | } 304 | break; 305 | 306 | case 'f': 307 | i = sscanf(optarg, "%f", &arg_f); 308 | if( (i != 1) || (arg_f < 1) ) 309 | { 310 | printf( "ERROR: argument parsing of -f argument. Use -h to print help\n" ); 311 | return EXIT_FAILURE; 312 | } 313 | else 314 | { 315 | freq_hz = (uint32_t)((arg_f * 1e6) + 0.5); 316 | } 317 | break; 318 | 319 | case 'r': 320 | i = sscanf(optarg, "%u", &arg_u); 321 | if( (i != 1) || (arg_u > 1) ) 322 | { 323 | printf( "ERROR: argument parsing of -r argument. Use -h to print help\n" ); 324 | return EXIT_FAILURE; 325 | } 326 | else 327 | { 328 | radio_select = (bool)arg_u; 329 | } 330 | break; 331 | 332 | default: 333 | printf( "ERROR: argument parsing options. Use -h to print help\n" ); 334 | return EXIT_FAILURE; 335 | } 336 | } 337 | 338 | /* Configure signal handling */ 339 | sigemptyset( &sigact.sa_mask ); 340 | sigact.sa_flags = 0; 341 | sigact.sa_handler = sig_handler; 342 | sigaction( SIGQUIT, &sigact, NULL ); 343 | sigaction( SIGINT, &sigact, NULL ); 344 | sigaction( SIGTERM, &sigact, NULL ); 345 | 346 | /* Decide if it is SX1257 or 55 depending on required freq*/ 347 | if (freq_hz > 700e6) { 348 | is_sx1255 = false; 349 | } else { 350 | is_sx1255 = true; 351 | } 352 | 353 | /* Connect to concentrator */ 354 | x = lgw_connect(); 355 | if (x == LGW_REG_ERROR) { 356 | printf("ERROR: FAIL TO CONNECT BOARD\n"); 357 | return LGW_HAL_ERROR; 358 | } 359 | 360 | /* reset the registers (also shuts the radios down) */ 361 | lgw_soft_reset(); 362 | wait_ms(100); 363 | 364 | /* switch on and reset the radios (also starts the 32 MHz XTAL) */ 365 | lgw_reg_w(LGW_RADIO_A_EN,1); 366 | lgw_reg_w(LGW_RADIO_B_EN,1); 367 | wait_ms(500); 368 | lgw_reg_w(LGW_RADIO_RST,1); 369 | wait_ms(1); 370 | lgw_reg_w(LGW_RADIO_RST,0); 371 | 372 | /* ~~~~~~ Setup SX1257 ~~~~~~ */ 373 | 374 | /* Check version */ 375 | if( sx125x_read(radio_select, 0x07) != SX125x_VERSION ) 376 | { 377 | printf( "ERROR: Bad SX1257 version\n" ); 378 | return EXIT_FAILURE; 379 | } 380 | 381 | sx125x_write(0, 0x10, SX125x_TX_DAC_CLK_SEL + 2); 382 | sx125x_write(1, 0x10, SX125x_TX_DAC_CLK_SEL + 2); 383 | if (is_sx1255) { 384 | sx125x_write(0, 0x28, SX125x_XOSC_GM_STARTUP + SX125x_XOSC_DISABLE*16); 385 | sx125x_write(1, 0x28, SX125x_XOSC_GM_STARTUP + SX125x_XOSC_DISABLE*16); 386 | } 387 | else { 388 | sx125x_write(0, 0x26, SX125x_XOSC_GM_STARTUP + SX125x_XOSC_DISABLE*16); 389 | sx125x_write(1, 0x26, SX125x_XOSC_GM_STARTUP + SX125x_XOSC_DISABLE*16); 390 | } 391 | 392 | /* Tx gain and BW */ 393 | sx125x_write( radio_select, 0x08, g_mix + g_dac*16); 394 | if( bw_khz > 250 ) 395 | { 396 | sx125x_write( radio_select, 0x0A, 12 + SX125x_TX_PLL_BW*32 ); /* ANA FILT BW */ 397 | sx125x_write( radio_select, 0x0B, 4 ); /* DIG FILT BW */ 398 | } 399 | else 400 | { 401 | sx125x_write( radio_select, 0x0A, 0 + SX125x_TX_PLL_BW*32 ); /* ANA FILT BW */ 402 | sx125x_write( radio_select, 0x0B, 5 ); /* DIG FILT BW */ 403 | } 404 | 405 | /* set TX PLL frequency */ 406 | if (is_sx1255) { 407 | part_int = freq_hz / (SX125x_32MHz_FRAC << 7); /* integer part, gives the MSB */ 408 | part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 7)) << 9) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */ 409 | } else { 410 | part_int = freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */ 411 | part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */ 412 | } 413 | sx125x_write(radio_select, 0x04,0xFF & part_int); /* Most Significant Byte */ 414 | sx125x_write(radio_select, 0x05,0xFF & (part_frac >> 8)); /* middle byte */ 415 | sx125x_write(radio_select, 0x06,0xFF & part_frac); /* Least Significant Byte */ 416 | 417 | /* Lock PLL and enable Tx */ 418 | sx125x_write(radio_select, 0x00, 1); 419 | wait_ms(1); 420 | sx125x_write(radio_select, 0x00, 13); 421 | wait_ms(10); 422 | if ((sx125x_read(radio_select, 0x11) & 0x01) == 0) { 423 | printf("ERROR: SX125x Tx PLL did not lock\n"); 424 | return -1; 425 | } 426 | 427 | /* ~~~~~~~~~~~~~~~~~~ */ 428 | 429 | /* Minimum SX1301 setup */ 430 | lgw_reg_w(LGW_GLOBAL_EN, 1); 431 | lgw_reg_w(LGW_TX_GAIN, g_dig); 432 | lgw_reg_w(LGW_PA_GAIN, g_pa); 433 | lgw_reg_w(LGW_TX_MODE, 1); // Tx continuous 434 | lgw_reg_w(LGW_FSK_TX_GAUSSIAN_SELECT_BT, bt); 435 | lgw_reg_w(LGW_GPIO_MODE,24); /* Set GPIO 3 and 4 in output to control potential Tx filter FPGA */ 436 | lgw_reg_w(LGW_GPIO_SELECT_OUTPUT,8); /* Control GPIO with register */ 437 | lgw_reg_w(LGW_GPIO_PIN_REG_OUT,16); /* Enable Tx */ 438 | 439 | if( strcmp( mod, "CW" ) == 0 ) 440 | { 441 | /* Enable signal generator with DC */ 442 | lgw_reg_w( LGW_SIG_GEN_FREQ, 0 ); 443 | lgw_reg_w( LGW_SIG_GEN_EN, 1 ); 444 | } 445 | else 446 | { 447 | /* Tx DC offset calibration */ 448 | x = load_firmware( 1, cal_tx_fw, 8192 ); /* Load firmware */ 449 | lgw_reg_w(LGW_RADIO_SELECT, (is_sx1255 << 5) | ((radio_select+1) << 2) ); /* Configure calibration */ 450 | lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL, 0); /* Give to MCU control of radio */ 451 | lgw_reg_w(LGW_MCU_RST_1, 0); 452 | lgw_reg_w(LGW_PAGE_REG, 3); /* Calibration start condition */ 453 | lgw_reg_w(LGW_EMERGENCY_FORCE_HOST_CTRL, 0); /* Give to MCU control of registers */ 454 | wait_ms(300); /* Wait enough until cal is done */ 455 | lgw_reg_w(LGW_EMERGENCY_FORCE_HOST_CTRL, 1); /* Get back control of registers */ 456 | 457 | /* Get calibration results */ 458 | lgw_reg_r( LGW_MCU_AGC_STATUS, &cal_status ); 459 | cal_status_expected = (1<<7) | ((radio_select+1)<<5) | (1<<2) | (1<<1) | 1; 460 | if (cal_status != cal_status_expected) 461 | { 462 | lgw_reg_w( LGW_TX_OFFSET_I, 0 ); 463 | lgw_reg_w( LGW_TX_OFFSET_Q, 0 ); 464 | printf("WARNING: Tx DC Calibration failed\n"); 465 | } 466 | 467 | /* TX metadata buffer */ 468 | if( strcmp( mod, "LORA" ) == 0 ) 469 | { 470 | buff[9] = sf; 471 | switch( bw_khz ) 472 | { 473 | case 125: buff[11] = 0; break; 474 | case 250: buff[11] = 1; break; 475 | case 500: buff[11] = 2; break; 476 | } 477 | buff[11] |= 0x04; /* set 'implicit header' bit */ 478 | } 479 | else if( strcmp( mod, "FSK" ) == 0 ) 480 | { 481 | br = (uint16_t)(32e3 / br_kbps); 482 | buff[7] = 1 << 4; 483 | buff[9] = fdev_khz; /* FSK frequency deviation */ 484 | buff[14] = 0xFF & (br >> 8); /* FSK bitrate */ 485 | buff[15] = 0xFF & br; 486 | } 487 | buff[10] = 1; /* payload size */ 488 | buff[12] = 0xFF & (65535 >> 8); /* preamble length */ 489 | buff[13] = 0xFF & 65535; 490 | 491 | /* Write metadata into buffer */ 492 | lgw_reg_w( LGW_TX_DATA_BUF_ADDR, 0 ); 493 | lgw_reg_wb( LGW_TX_DATA_BUF_DATA, buff, 16 ); 494 | 495 | /* Trig Tx and check modulation is running */ 496 | lgw_reg_w( LGW_TX_TRIG_IMMEDIATE, 1 ); 497 | wait_ms(5); 498 | lgw_reg_r( LGW_TX_STATUS, &tx_status ); 499 | if( tx_status != 80 ) 500 | { 501 | printf( "ERROR: modulation not running\n" ); 502 | return EXIT_FAILURE; 503 | } 504 | } 505 | 506 | /* Load firmware to select radio */ 507 | x = load_firmware( 1, util_fw, 8192 ); 508 | lgw_reg_w(LGW_MCU_RST_1, 0); 509 | lgw_reg_w(LGW_RADIO_SELECT, radio_select); 510 | 511 | /* Set RF switch in Tx */ 512 | if( radio_select ) 513 | { 514 | lgw_reg_w(LGW_PA_B_EN,1); 515 | } else 516 | { 517 | lgw_reg_w(LGW_PA_A_EN,1); 518 | } 519 | 520 | /* Enable Tx and Tx narrowband filter for LORA 125kHz BW */ 521 | if( ( strcmp( mod, "LORA" ) == 0 ) && ( bw_khz == 125 ) ) 522 | { 523 | lgw_reg_w(LGW_GPIO_PIN_REG_OUT,24); 524 | } 525 | 526 | /* Recap all settings */ 527 | printf( "SX1301 library version: %s\n", lgw_version_info( ) ); 528 | if( strcmp( mod, "LORA" ) == 0 ) 529 | { 530 | printf( "Modulation: LORA SF:%d BW:%d kHz\n", sf, bw_khz ); 531 | } 532 | else if( strcmp( mod, "FSK" ) == 0 ) 533 | { 534 | printf( "Modulation: FSK BR:%3.3f kbps FDEV:%d kHz BT:%d\n", br_kbps, fdev_khz, bt ); 535 | } 536 | else if( strcmp( mod, "CW" ) == 0 ) 537 | { 538 | printf( "Modulation: CW\n" ); 539 | } 540 | if( radio_select ) 541 | { 542 | printf("Radio: B\n"); 543 | } 544 | else 545 | { 546 | printf("Radio: A\n"); 547 | } 548 | printf( "Frequency: %4.3f MHz\n", freq_hz/1e6 ); 549 | printf( "Expected chip: SX125%d\n", 7-is_sx1255*2 ); 550 | printf( "Gains: Digital:%d DAC:%d Mixer:%d PA:%d\n", g_dig, g_dac, g_mix, g_pa ); 551 | if( strcmp( mod, "CW" ) != 0 ) 552 | { 553 | lgw_reg_r( LGW_TX_OFFSET_I, &offset_i ); 554 | lgw_reg_r( LGW_TX_OFFSET_Q, &offset_q ); 555 | printf( "Calibrated DC offsets: I:%d Q:%d\n", offset_i, offset_q ); 556 | } 557 | 558 | /* waiting for user input */ 559 | while ((quit_sig != 1) && (exit_sig != 1)) 560 | { 561 | wait_ms(100); 562 | } 563 | 564 | /* clean up before leaving */ 565 | lgw_stop(); 566 | 567 | return 0; 568 | } 569 | 570 | /* -------------------------------------------------------------------------- */ 571 | /* --- SUBFUNCTIONS DEFINITION ---------------------------------------------- */ 572 | 573 | static void sig_handler( int sigio ) 574 | { 575 | if( sigio == SIGQUIT ) 576 | { 577 | quit_sig = 1; 578 | } 579 | else if( (sigio == SIGINT) || (sigio == SIGTERM) ) 580 | { 581 | exit_sig = 1; 582 | } 583 | } 584 | 585 | /* --- EOF ------------------------------------------------------------------ */ 586 | -------------------------------------------------------------------------------- /util_tx_test/Makefile: -------------------------------------------------------------------------------- 1 | ### Application-specific constants 2 | 3 | APP_NAME := util_tx_test 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 | ### Constants for LoRa concentrator HAL library 24 | # List the library sub-modules that are used by the application 25 | 26 | LGW_INC = $(LGW_PATH)/inc/config.h 27 | LGW_INC += $(LGW_PATH)/inc/loragw_hal.h 28 | LGW_INC += $(LGW_PATH)/inc/loragw_aux.h 29 | 30 | ### Linking options 31 | 32 | ifeq ($(CFG_SPI),native) 33 | LIBS := -lloragw -lrt 34 | else ifeq ($(CFG_SPI),ftdi) 35 | LIBS := -lloragw -lrt -lmpsse 36 | endif 37 | 38 | ### General build targets 39 | 40 | all: $(APP_NAME) 41 | 42 | clean: 43 | rm -f obj/*.o 44 | rm -f $(APP_NAME) 45 | 46 | ### HAL library (do no force multiple library rebuild even with 'make -B') 47 | 48 | $(LGW_PATH)/inc/config.h: 49 | @if test ! -f $@; then \ 50 | $(MAKE) all -C $(LGW_PATH); \ 51 | fi 52 | 53 | $(LGW_PATH)/libloragw.a: $(LGW_INC) 54 | @if test ! -f $@; then \ 55 | $(MAKE) all -C $(LGW_PATH); \ 56 | fi 57 | 58 | ### Main program compilation and assembly 59 | 60 | obj/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) 61 | $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@ 62 | 63 | $(APP_NAME): obj/$(APP_NAME).o $(LGW_PATH)/libloragw.a 64 | $(CC) -L$(LGW_PATH) $< -o $@ $(LIBS) 65 | 66 | ### EOF 67 | -------------------------------------------------------------------------------- /util_tx_test/obj/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirakonta/lora_gateway/0642acb11d56150f619d76f809fdfa48280df80e/util_tx_test/obj/.gitkeep -------------------------------------------------------------------------------- /util_tx_test/readme.md: -------------------------------------------------------------------------------- 1 | / _____) _ | | 2 | ( (____ _____ ____ _| |_ _____ ____| |__ 3 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 4 | _____) ) ____| | | || |_| ____( (___| | | | 5 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 6 | (C)2013 Semtech-Cycleo 7 | 8 | LoRa concentrator packet sender 9 | ================================ 10 | 11 | 1. Introduction 12 | ---------------- 13 | 14 | This software is used to send test packets with a LoRa concentrator. The packets 15 | contain little information, on no protocol (ie. MAC address) information but 16 | can be used to assess the functionality of a gateway downlink using other 17 | gateways as receivers. 18 | 19 | 2. Dependencies 20 | ---------------- 21 | 22 | This program is a typical example of LoRa concentrator HAL usage for sending 23 | packets. 24 | 25 | Only high-level functions are used (the ones contained in loragw_hal) so there 26 | is no hardware dependencies assuming the HAL is matched with the proper version 27 | of the hardware. 28 | Data structures of the sent packets are accessed by name (ie. not at a 29 | binary level) so new functionalities can be added to the API without affecting 30 | that program at all. 31 | 32 | It was tested with v1.3.0 of the libloragw library, and should be compatible 33 | with any later version of the library assuming the API is downward-compatible. 34 | 35 | 3. Usage 36 | --------- 37 | 38 | The application runs until the specified number of packets have been sent. 39 | Press Ctrl+C to stop the application before that. 40 | 41 | Use the -f option followed by a real number (decimal point and scientific 42 | 'E notation' are OK) to specify the modulation central frequency. 43 | 44 | Use the -b option to set LoRa modulation bandwidth in kHz (accepted values: 125, 45 | 250 or 500). 46 | 47 | Use the -s option to specify the Spreading Factor of LoRa modulation (values 7 48 | to 12 are valid). 49 | 50 | Use the -c option to specify the Coding Rate of LoRa modulation ( 1 = 4/5, 2 = 51 | 4/6, 3 = 4/7, 4 = 4/8 ). 52 | 53 | Use the -p option to set the concentrator TX power in dBm. Not all values are 54 | supported by hardware (typically 14 et 20 dBm are supported, other values might 55 | not give expected power). Check with a RF power meter before connecting any 56 | sensitive equipment. 57 | 58 | Use the -r option to set LoRa preamble size. A minimum preamble length of 6 59 | symbols is enforced. 60 | 61 | Use the -z option to set the payload size in bytes. 62 | 63 | Use the -t option to specify the number of milliseconds of pause between 64 | packets. Using zero will result in a quasi-continuous emission. 65 | 66 | Use the -x option to specify how many packets should be sent. The value -1 cause 67 | the program to send packet indefinitely, until stopped (using Ctrl-C). 68 | 69 | Use the -i option to invert the LoRa modulation polarity. 70 | 71 | The payload content is: 72 | [T][E][S][T][packet counter MSB][packet counter LSB] followed by ASCII padding. 73 | 74 | All LoRa data is scrambled and whitened, so the padding has no influence 75 | whatsoever on the packet error rate. 76 | 77 | 4. License 78 | ----------- 79 | 80 | Copyright (c) 2013, SEMTECH S.A. 81 | All rights reserved. 82 | 83 | Redistribution and use in source and binary forms, with or without 84 | modification, are permitted provided that the following conditions are met: 85 | 86 | * Redistributions of source code must retain the above copyright 87 | notice, this list of conditions and the following disclaimer. 88 | * Redistributions in binary form must reproduce the above copyright 89 | notice, this list of conditions and the following disclaimer in the 90 | documentation and/or other materials provided with the distribution. 91 | * Neither the name of the Semtech corporation nor the 92 | names of its contributors may be used to endorse or promote products 93 | derived from this software without specific prior written permission. 94 | 95 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 96 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 97 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 98 | DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY 99 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 100 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 101 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 102 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 103 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 104 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 105 | 106 | *EOF* -------------------------------------------------------------------------------- /util_tx_test/src/util_tx_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech-Cycleo 8 | 9 | Description: 10 | Send a bunch of packets on a settable frequency 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 fprintf sprintf fopen fputs */ 30 | 31 | #include /* memset */ 32 | #include /* sigaction */ 33 | #include /* getopt access */ 34 | #include /* exit codes */ 35 | 36 | #include "loragw_hal.h" 37 | #include "loragw_aux.h" 38 | 39 | /* -------------------------------------------------------------------------- */ 40 | /* --- PRIVATE MACROS ------------------------------------------------------- */ 41 | 42 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 43 | #define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */ 44 | 45 | /* -------------------------------------------------------------------------- */ 46 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ 47 | 48 | #define RF_CHAIN 0 /* we'll use radio A only */ 49 | #define DEFAULT_RSSI_OFFSET 0.0 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 | printf("*** Library version information ***\n%s\n\n", lgw_version_info()); 80 | printf("Available options:\n"); 81 | printf(" -h print this help\n"); 82 | printf(" -r radio type (SX1255:1255, SX1257:1257)\n"); 83 | printf(" -f target frequency in MHz\n"); 84 | printf(" -b LoRa bandwidth in kHz [125, 250, 500]\n"); 85 | printf(" -s LoRa Spreading Factor [7-12]\n"); 86 | printf(" -c LoRa Coding Rate [1-4]\n"); 87 | printf(" -p RF power (dBm)\n"); 88 | printf(" -l LoRa preamble length (symbols)\n"); 89 | printf(" -z payload size (bytes, <256)\n"); 90 | printf(" -t pause between packets (ms)\n"); 91 | printf(" -x nb of times the sequence is repeated (-1 loop until stopped)\n"); 92 | printf(" -i send packet using inverted modulation polarity\n"); 93 | } 94 | 95 | /* -------------------------------------------------------------------------- */ 96 | /* --- MAIN FUNCTION -------------------------------------------------------- */ 97 | 98 | int main(int argc, char **argv) 99 | { 100 | int i; 101 | uint8_t status_var; 102 | 103 | /* user entry parameters */ 104 | int xi = 0; 105 | double xd = 0.0; 106 | 107 | /* application parameters */ 108 | uint32_t f_target = 0; /* target frequency - invalid default value, has to be specified by user */ 109 | int sf = 10; /* SF10 by default */ 110 | int cr = 1; /* CR1 aka 4/5 by default */ 111 | int bw = 125; /* 125kHz bandwidth by default */ 112 | int pow = 14; /* 14 dBm by default */ 113 | int preamb = 8; /* 8 symbol preamble by default */ 114 | int pl_size = 16; /* 16 bytes payload by default */ 115 | int delay = 1000; /* 1 second between packets by default */ 116 | int repeat = -1; /* by default, repeat until stopped */ 117 | bool invert = false; 118 | 119 | /* RF configuration (TX fail if RF chain is not enabled) */ 120 | enum lgw_radio_type_e radio_type = LGW_RADIO_TYPE_NONE; 121 | uint8_t clocksource = 0; /* Radio A is source in MTAC-LORA */ 122 | struct lgw_conf_board_s boardconf; 123 | struct lgw_conf_rxrf_s rfconf; 124 | 125 | /* allocate memory for packet sending */ 126 | struct lgw_pkt_tx_s txpkt; /* array containing 1 outbound packet + metadata */ 127 | 128 | /* loop variables (also use as counters in the packet payload) */ 129 | uint16_t cycle_count = 0; 130 | 131 | /* parse command line options */ 132 | while ((i = getopt (argc, argv, "hif:b:s:c:p:l:z:t:x:r:k")) != -1) { 133 | switch (i) { 134 | case 'h': 135 | usage(); 136 | return EXIT_FAILURE; 137 | break; 138 | 139 | case 'f': /* -f target frequency in MHz */ 140 | i = sscanf(optarg, "%lf", &xd); 141 | if ((i != 1) || (xd < 30.0) || (xd > 3000.0)) { 142 | MSG("ERROR: invalid TX frequency\n"); 143 | usage(); 144 | return EXIT_FAILURE; 145 | } else { 146 | f_target = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ 147 | } 148 | break; 149 | 150 | case 'b': /* -b Modulation bandwidth in kHz */ 151 | i = sscanf(optarg, "%i", &xi); 152 | if ((i != 1) || ((xi != 125)&&(xi != 250)&&(xi != 500))) { 153 | MSG("ERROR: invalid LoRa bandwidth\n"); 154 | usage(); 155 | return EXIT_FAILURE; 156 | } else { 157 | bw = xi; 158 | } 159 | break; 160 | 161 | case 's': /* -s Spreading Factor */ 162 | i = sscanf(optarg, "%i", &xi); 163 | if ((i != 1) || (xi < 7) || (xi > 12)) { 164 | MSG("ERROR: invalid spreading factor\n"); 165 | usage(); 166 | return EXIT_FAILURE; 167 | } else { 168 | sf = xi; 169 | } 170 | break; 171 | 172 | case 'c': /* -c Coding Rate */ 173 | i = sscanf(optarg, "%i", &xi); 174 | if ((i != 1) || (xi < 1) || (xi > 4)) { 175 | MSG("ERROR: invalid coding rate\n"); 176 | usage(); 177 | return EXIT_FAILURE; 178 | } else { 179 | cr = xi; 180 | } 181 | break; 182 | 183 | case 'p': /* -p RF power */ 184 | i = sscanf(optarg, "%i", &xi); 185 | if ((i != 1) || (xi < -60) || (xi > 60)) { 186 | MSG("ERROR: invalid RF power\n"); 187 | usage(); 188 | return EXIT_FAILURE; 189 | } else { 190 | pow = xi; 191 | } 192 | break; 193 | 194 | case 'l': /* -r preamble length (symbols) */ 195 | i = sscanf(optarg, "%i", &xi); 196 | if ((i != 1) || (xi < 6)) { 197 | MSG("ERROR: preamble length must be >6 symbols \n"); 198 | usage(); 199 | return EXIT_FAILURE; 200 | } else { 201 | preamb = xi; 202 | } 203 | break; 204 | 205 | case 'z': /* -z payload length (bytes) */ 206 | i = sscanf(optarg, "%i", &xi); 207 | if ((i != 1) || (xi <= 0)) { 208 | MSG("ERROR: invalid payload size\n"); 209 | usage(); 210 | return EXIT_FAILURE; 211 | } else { 212 | pl_size = xi; 213 | } 214 | break; 215 | 216 | case 't': /* -t pause between packets (ms) */ 217 | i = sscanf(optarg, "%i", &xi); 218 | if ((i != 1) || (xi < 0)) { 219 | MSG("ERROR: invalid time between packets\n"); 220 | usage(); 221 | return EXIT_FAILURE; 222 | } else { 223 | delay = xi; 224 | } 225 | break; 226 | 227 | case 'x': /* -x numbers of times the sequence is repeated */ 228 | i = sscanf(optarg, "%i", &xi); 229 | if ((i != 1) || (xi < -1)) { 230 | MSG("ERROR: invalid number of repeats\n"); 231 | usage(); 232 | return EXIT_FAILURE; 233 | } else { 234 | repeat = xi; 235 | } 236 | break; 237 | 238 | case 'r': /* Radio type (1255, 1257) */ 239 | sscanf(optarg, "%i", &xi); 240 | switch (xi) { 241 | case 1255: 242 | radio_type = LGW_RADIO_TYPE_SX1255; 243 | break; 244 | case 1257: 245 | radio_type = LGW_RADIO_TYPE_SX1257; 246 | break; 247 | default: 248 | printf("ERROR: invalid radio type\n"); 249 | usage(); 250 | return EXIT_FAILURE; 251 | } 252 | break; 253 | 254 | case 'i': /* -i send packet using inverted modulation polarity */ 255 | invert = true; 256 | break; 257 | 258 | case 'k': /* Concentrator clock source (Radio A(default in MTAC-LORA) or Radio B) */ 259 | sscanf(optarg, "%i", &xi); 260 | clocksource = (uint8_t)xi; 261 | break; 262 | 263 | default: 264 | MSG("ERROR: argument parsing\n"); 265 | usage(); 266 | return EXIT_FAILURE; 267 | } 268 | } 269 | 270 | /* check parameter sanity */ 271 | if (f_target == 0) { 272 | MSG("ERROR: frequency parameter not set, please use -f option to specify it.\n"); 273 | return EXIT_FAILURE; 274 | } 275 | if (radio_type == LGW_RADIO_TYPE_NONE) { 276 | MSG("ERROR: radio type parameter not properly set, please use -r option to specify it.\n"); 277 | return EXIT_FAILURE; 278 | } 279 | printf("Sending %i packets on %u Hz (BW %i kHz, SF %i, CR %i, %i bytes payload, %i symbols preamble) at %i dBm, with %i ms between each\n", repeat, f_target, bw, sf, cr, pl_size, preamb, pow, delay); 280 | 281 | /* configure signal handling */ 282 | sigemptyset(&sigact.sa_mask); 283 | sigact.sa_flags = 0; 284 | sigact.sa_handler = sig_handler; 285 | sigaction(SIGQUIT, &sigact, NULL); 286 | sigaction(SIGINT, &sigact, NULL); 287 | sigaction(SIGTERM, &sigact, NULL); 288 | 289 | /* starting the concentrator */ 290 | /* board config */ 291 | memset(&boardconf, 0, sizeof(boardconf)); 292 | 293 | boardconf.lorawan_public = true; 294 | boardconf.clksrc = clocksource; 295 | lgw_board_setconf(boardconf); 296 | 297 | /* RF config */ 298 | memset(&rfconf, 0, sizeof(rfconf)); 299 | 300 | rfconf.enable = true; 301 | rfconf.freq_hz = f_target; 302 | rfconf.rssi_offset = DEFAULT_RSSI_OFFSET; 303 | rfconf.type = radio_type; 304 | rfconf.tx_enable = true; 305 | lgw_rxrf_setconf(RF_CHAIN, rfconf); 306 | 307 | i = lgw_start(); 308 | if (i == LGW_HAL_SUCCESS) { 309 | MSG("INFO: concentrator started, packet can be sent\n"); 310 | } else { 311 | MSG("ERROR: failed to start the concentrator\n"); 312 | return EXIT_FAILURE; 313 | } 314 | 315 | /* fill-up payload and parameters */ 316 | memset(&txpkt, 0, sizeof(txpkt)); 317 | txpkt.freq_hz = f_target; 318 | txpkt.tx_mode = IMMEDIATE; 319 | txpkt.rf_chain = RF_CHAIN; 320 | txpkt.rf_power = pow; 321 | txpkt.modulation = MOD_LORA; 322 | switch (bw) { 323 | case 125: txpkt.bandwidth = BW_125KHZ; break; 324 | case 250: txpkt.bandwidth = BW_250KHZ; break; 325 | case 500: txpkt.bandwidth = BW_500KHZ; break; 326 | default: 327 | MSG("ERROR: invalid 'bw' variable\n"); 328 | return EXIT_FAILURE; 329 | } 330 | switch (sf) { 331 | case 7: txpkt.datarate = DR_LORA_SF7; break; 332 | case 8: txpkt.datarate = DR_LORA_SF8; break; 333 | case 9: txpkt.datarate = DR_LORA_SF9; break; 334 | case 10: txpkt.datarate = DR_LORA_SF10; break; 335 | case 11: txpkt.datarate = DR_LORA_SF11; break; 336 | case 12: txpkt.datarate = DR_LORA_SF12; break; 337 | default: 338 | MSG("ERROR: invalid 'sf' variable\n"); 339 | return EXIT_FAILURE; 340 | } 341 | switch (cr) { 342 | case 1: txpkt.coderate = CR_LORA_4_5; break; 343 | case 2: txpkt.coderate = CR_LORA_4_6; break; 344 | case 3: txpkt.coderate = CR_LORA_4_7; break; 345 | case 4: txpkt.coderate = CR_LORA_4_8; break; 346 | default: 347 | MSG("ERROR: invalid 'cr' variable\n"); 348 | return EXIT_FAILURE; 349 | } 350 | txpkt.invert_pol = invert; 351 | txpkt.preamble = preamb; 352 | txpkt.size = pl_size; 353 | strcpy((char *)txpkt.payload, "TEST**abcdefghijklmnopqrstuvwxyz#0123456789#ABCDEFGHIJKLMNOPQRSTUVWXYZ#0123456789#abcdefghijklmnopqrstuvwxyz#0123456789#ABCDEFGHIJKLMNOPQRSTUVWXYZ#0123456789#abcdefghijklmnopqrstuvwxyz#0123456789#ABCDEFGHIJKLMNOPQRSTUVWXYZ#0123456789#abcdefghijklmnopqrs#" ); /* abc.. is for padding */ 354 | 355 | /* main loop */ 356 | cycle_count = 0; 357 | while ((repeat == -1) || (cycle_count < repeat)) { 358 | ++cycle_count; 359 | 360 | /* refresh counters in payload (big endian, for readability) */ 361 | txpkt.payload[4] = (uint8_t)(cycle_count >> 8); /* MSB */ 362 | txpkt.payload[5] = (uint8_t)(cycle_count & 0x00FF); /* LSB */ 363 | 364 | /* send packet */ 365 | printf("Sending packet number %u ...", cycle_count); 366 | i = lgw_send(txpkt); /* non-blocking scheduling of TX packet */ 367 | if (i != LGW_HAL_SUCCESS) { 368 | printf("ERROR\n"); 369 | return EXIT_FAILURE; 370 | } 371 | 372 | /* wait for packet to finish sending */ 373 | do { 374 | wait_ms(5); 375 | lgw_status(TX_STATUS, &status_var); /* get TX status */ 376 | } while (status_var != TX_FREE); 377 | printf("OK\n"); 378 | 379 | /* wait inter-packet delay */ 380 | wait_ms(delay); 381 | 382 | /* exit loop on user signals */ 383 | if ((quit_sig == 1) || (exit_sig == 1)) { 384 | break; 385 | } 386 | } 387 | 388 | /* clean up before leaving */ 389 | lgw_stop(); 390 | 391 | printf("Exiting LoRa concentrator TX test program\n"); 392 | return EXIT_SUCCESS; 393 | } 394 | 395 | /* --- EOF ------------------------------------------------------------------ */ 396 | --------------------------------------------------------------------------------