From f991b0e35ad1bd3b999c70e68c518bae91bd36a6 Mon Sep 17 00:00:00 2001 From: Sylvain Miermont Date: Fri, 28 Mar 2014 16:58:48 +0100 Subject: v1.3.0 - Added TX power management. - Added full support for SX1301 reference board. - Changed build system with configuration for multiple chip/radio/band support. - SX125x bandwidth set to 1MHz by default (was 800 kHz). - Solved warnings with 64b integer printf when compiling on x86_64. - Renamed helper programs to reduce the concentrator vs. gateway confusion. --- util_tx_test/Makefile | 58 +++++++ util_tx_test/obj/.gitkeep | 0 util_tx_test/readme.md | 98 ++++++++++++ util_tx_test/src/util_tx_test.c | 335 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 491 insertions(+) create mode 100644 util_tx_test/Makefile create mode 100644 util_tx_test/obj/.gitkeep create mode 100644 util_tx_test/readme.md create mode 100644 util_tx_test/src/util_tx_test.c (limited to 'util_tx_test') diff --git a/util_tx_test/Makefile b/util_tx_test/Makefile new file mode 100644 index 0000000..2c457e7 --- /dev/null +++ b/util_tx_test/Makefile @@ -0,0 +1,58 @@ +### Application-specific constants + +APP_NAME := util_tx_test + +### Environment constants + +LGW_PATH := ../libloragw +CROSS_COMPILE := + +### External constant definitions +# must get library build option to know if mpsse must be linked or not + +include $(LGW_PATH)/library.cfg + +### Constant symbols + +CC := $(CROSS_COMPILE)gcc +AR := $(CROSS_COMPILE)ar + +CFLAGS=-O2 -Wall -Wextra -std=c99 -Iinc -I. + +### Constants for LoRa concentrator HAL library +# List the library sub-modules that are used by the application + +LGW_INC = $(LGW_PATH)/inc/config.h +LGW_INC += $(LGW_PATH)/inc/loragw_hal.h +LGW_INC += $(LGW_PATH)/inc/loragw_aux.h + +### Linking options + +ifeq ($(CFG_SPI),native) + LIBS := -lloragw -lrt +else ifeq ($(CFG_SPI),ftdi) + LIBS := -lloragw -lrt -lmpsse +endif + +### General build targets + +all: $(APP_NAME) + +clean: + rm -f obj/*.o + rm -f $(APP_NAME) + +### HAL library + +$(LGW_PATH)/libloragw.a: $(LGW_INC) + $(MAKE) all -C $(LGW_PATH) + +### Main program compilation and assembly + +obj/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) + $(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@ + +$(APP_NAME): obj/$(APP_NAME).o $(LGW_PATH)/libloragw.a + $(CC) -L$(LGW_PATH) $< -o $@ $(LIBS) + +### EOF \ No newline at end of file diff --git a/util_tx_test/obj/.gitkeep b/util_tx_test/obj/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/util_tx_test/readme.md b/util_tx_test/readme.md new file mode 100644 index 0000000..5450f18 --- /dev/null +++ b/util_tx_test/readme.md @@ -0,0 +1,98 @@ + / _____) _ | | + ( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | + (______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech-Cycleo + +LoRa concentrator packet sender +================================ + +1. Introduction +---------------- + +This software is used to send test packets with a LoRa concentrator. The packets +contain little information, on no protocol (ie. MAC address) information but +can be used to assess the functionality of a gateway downlink using other +gateways as receivers. + +2. Dependencies +---------------- + +This program is a typical example of LoRa concentrator HAL usage for sending +packets. + +Only high-level functions are used (the ones contained in loragw_hal) so there +is no hardware dependencies assuming the HAL is matched with the proper version +of the hardware. +Data structures of the sent packets are accessed by name (ie. not at a +binary level) so new functionalities can be added to the API without affecting +that program at all. + +It was tested with v1.3.0 of the libloragw library, and should be compatible +with any later version of the library assuming the API is downward-compatible. + +3. Usage +--------- + +The application runs until the specified number of packets have been sent. +Press Ctrl+C to stop the application before that. + +Use the -f option followed by a real number (decimal point and scientific +'E notation' are OK) to specify the modulation central frequency. + +Use the -s option to specify the Spreading Factor of LoRa modulation (values 7 +to 12 are valid). + +Use the -b option to set LoRa modulation bandwidth in kHz (accepted values: 125, +250 or 500). + +Use the -p option to set the concentrator TX power in dBm. Not all values are +supported by hardware (typically 14 et 20 dBm are supported, other values might +not give expected power). Check with a RF power meter before connecting any +sensitive equipment. + +Use the -t option to specify the number of milliseconds of pause between +packets. Using zero will result in a quasi-continuous emission. + +Use the -x option to specify how many packets should be sent. + +Use the -i option to invert the LoRa modulation polarity. + +The packets are 20 bytes long, and protected by the smallest supported ECC. + +The payload content is: +[T][E][S][T][packet counter MSB][packet counter LSB] followed by ASCII padding. +All LoRa data is whitened, so the padding has no influence whatsoever on the +packet error rate. + +4. License +----------- + +Copyright (c) 2013, SEMTECH S.A. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of the Semtech corporation nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*EOF* \ No newline at end of file diff --git a/util_tx_test/src/util_tx_test.c b/util_tx_test/src/util_tx_test.c new file mode 100644 index 0000000..bb7672b --- /dev/null +++ b/util_tx_test/src/util_tx_test.c @@ -0,0 +1,335 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech-Cycleo + +Description: + Send a bunch of packets on a settable frequency + +License: Revised BSD License, see LICENSE.TXT file include in the project +Maintainer: Sylvain Miermont +*/ + + +/* -------------------------------------------------------------------------- */ +/* --- DEPENDANCIES --------------------------------------------------------- */ + +/* fix an issue between POSIX and C99 */ +#if __STDC_VERSION__ >= 199901L + #define _XOPEN_SOURCE 600 +#else + #define _XOPEN_SOURCE 500 +#endif + +#include /* C99 types */ +#include /* bool type */ +#include /* printf fprintf sprintf fopen fputs */ + +#include /* memset */ +#include /* sigaction */ +#include /* getopt access */ +#include /* exit codes */ + +#include "loragw_hal.h" +#include "loragw_aux.h" + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE MACROS ------------------------------------------------------- */ + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define MSG(args...) fprintf(stderr, args) /* message that is destined to the user */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ + +#define RF_CHAIN 0 /* we'll use radio A only */ + +const uint32_t lowfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_LOWFREQ; +const uint32_t upfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_UPFREQ; + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ + +/* signal handling variables */ +struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ +static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ +static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ + +static void sig_handler(int sigio); + +void usage (void); + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ + +static void sig_handler(int sigio) { + if (sigio == SIGQUIT) { + quit_sig = 1;; + } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { + exit_sig = 1; + } +} + +/* describe command line options */ +void usage(void) { + printf("*** Library version information ***\n%s\n\n", lgw_version_info()); + printf( "Available options:\n"); + printf( " -h print this help\n"); + printf( " -f target frequency in MHz\n"); + printf( " -s Spreading Factor\n"); + printf( " -b Modulation bandwidth in kHz\n"); + printf( " -p RF power (dBm)\n"); + printf( " -r LoRa preamble length (symbols)\n"); + printf( " -z payload size (bytes)\n"); + printf( " -t pause between packets (ms)\n"); + printf( " -x numbers of times the sequence is repeated (-1 for continuous)\n"); + printf( " -i send packet using inverted modulation polarity \n"); +} + +/* -------------------------------------------------------------------------- */ +/* --- MAIN FUNCTION -------------------------------------------------------- */ + +int main(int argc, char **argv) +{ + int i; + uint8_t status_var; + + /* user entry parameters */ + int xi = 0; + double xd = 0.0; + uint32_t f_min; + uint32_t f_max; + + /* application parameters */ + uint32_t f_target = lowfreq[RF_CHAIN]/2 + upfreq[RF_CHAIN]/2; /* target frequency */ + int sf = 10; /* SF10 by default */ + int bw = 125; /* 125kHz bandwidth by default */ + int pow = 14; /* 14 dBm by default */ + int preamb = 8; /* 8 symbol preamble by default */ + int pl_size = 16; /* 16 bytes payload by default */ + int delay = 1000; /* 1 second between packets by default */ + int repeat = -1; /* by default, repeat until stopped */ + bool invert = false; + + /* RF configuration (TX fail if RF chain is not enabled) */ + const struct lgw_conf_rxrf_s rfconf = {true, lowfreq[RF_CHAIN]}; + + /* allocate memory for packet sending */ + struct lgw_pkt_tx_s txpkt; /* array containing 1 outbound packet + metadata */ + + /* loop variables (also use as counters in the packet payload) */ + uint16_t cycle_count = 0; + + /* parse command line options */ + while ((i = getopt (argc, argv, "hf:s:b:p:r:z:t:x:i")) != -1) { + switch (i) { + case 'h': + usage(); + return EXIT_FAILURE; + break; + + case 'f': /* -f target frequency in MHz */ + i = sscanf(optarg, "%lf", &xd); + if ((i != 1) || (xd < 30.0) || (xd > 3000.0)) { + MSG("ERROR: invalid TX frequency\n"); + usage(); + return EXIT_FAILURE; + } else { + f_target = (uint32_t)((xd*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */ + } + break; + + case 's': /* -s Spreading Factor */ + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || (xi < 7) || (xi > 12)) { + MSG("ERROR: invalid spreading factor\n"); + usage(); + return EXIT_FAILURE; + } else { + sf = xi; + } + break; + + case 'b': /* -b Modulation bandwidth in kHz */ + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || ((xi != 125)&&(xi != 250)&&(xi != 500))) { + MSG("ERROR: invalid LoRa bandwidth\n"); + usage(); + return EXIT_FAILURE; + } else { + bw = xi; + } + break; + + case 'p': /* -p RF power */ + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || (xi < -60) || (xi > 60)) { + MSG("ERROR: invalid RF power\n"); + usage(); + return EXIT_FAILURE; + } else { + pow = xi; + } + break; + + case 'r': /* -r preamble length (symbols) */ + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || (xi < 6)) { + MSG("ERROR: preamble length must be >6 symbols \n"); + usage(); + return EXIT_FAILURE; + } else { + preamb = xi; + } + break; + + case 'z': /* -z payload length (bytes) */ + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || (xi <= 0)) { + MSG("ERROR: invalid payload size\n"); + usage(); + return EXIT_FAILURE; + } else { + pl_size = xi; + } + break; + + case 't': /* -t pause between packets (ms) */ + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || (xi < 0)) { + MSG("ERROR: invalid time between packets\n"); + usage(); + return EXIT_FAILURE; + } else { + delay = xi; + } + break; + + case 'x': /* -x numbers of times the sequence is repeated */ + i = sscanf(optarg, "%i", &xi); + if ((i != 1) || (xi < -1)) { + MSG("ERROR: invalid number of repeats\n"); + usage(); + return EXIT_FAILURE; + } else { + repeat = xi; + } + break; + + case 'i': /* -i send packet using inverted modulation polarity */ + invert = true; + break; + + default: + MSG("ERROR: argument parsing\n"); + usage(); + return EXIT_FAILURE; + } + } + + /* check parameter sanity */ + f_min = lowfreq[RF_CHAIN] + (500 * bw); + f_max = upfreq[RF_CHAIN] - (500 * bw); + if ((f_target < f_min) || (f_target > f_max)) { + MSG("ERROR: frequency out of authorized band (accounting for modulation bandwidth)\n"); + return EXIT_FAILURE; + } + printf("Sending %i packets on %u Hz (BW %i kHz, SF %i, %i bytes payload, %i symbols preamble) at %i dBm, with %i ms between each\n", repeat, f_target, bw, sf, pl_size, preamb, pow, delay); + + /* configure signal handling */ + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigact.sa_handler = sig_handler; + sigaction(SIGQUIT, &sigact, NULL); + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + + /* starting the concentrator */ + lgw_rxrf_setconf(RF_CHAIN, rfconf); + i = lgw_start(); + if (i == LGW_HAL_SUCCESS) { + MSG("INFO: concentrator started, packet can be sent\n"); + } else { + MSG("ERROR: failed to start the concentrator\n"); + return EXIT_FAILURE; + } + + /* fill-up payload and parameters */ + memset(&txpkt, 0, sizeof(txpkt)); + txpkt.freq_hz = f_target; + txpkt.tx_mode = IMMEDIATE; + txpkt.rf_chain = RF_CHAIN; + txpkt.rf_power = pow; + txpkt.modulation = MOD_LORA; + switch (bw) { + case 125: txpkt.bandwidth = BW_125KHZ; break; + case 250: txpkt.bandwidth = BW_250KHZ; break; + case 500: txpkt.bandwidth = BW_500KHZ; break; + default: + MSG("ERROR: invalid 'bw' variable\n"); + return EXIT_FAILURE; + } + switch (sf) { + case 7: txpkt.datarate = DR_LORA_SF7; break; + case 8: txpkt.datarate = DR_LORA_SF8; break; + case 9: txpkt.datarate = DR_LORA_SF9; break; + case 10: txpkt.datarate = DR_LORA_SF10; break; + case 11: txpkt.datarate = DR_LORA_SF11; break; + case 12: txpkt.datarate = DR_LORA_SF12; break; + default: + MSG("ERROR: invalid 'sf' variable\n"); + return EXIT_FAILURE; + } + txpkt.coderate = CR_LORA_4_5; + txpkt.invert_pol = invert; + txpkt.preamble = preamb; + txpkt.size = pl_size; + strcpy((char *)txpkt.payload, "TEST**abcdefghijklmnopqrstuvwxyz0123456789" ); /* abc.. is for padding */ + + /* main loop */ + cycle_count = 0; + while ((repeat == -1) || (cycle_count < repeat)) { + ++cycle_count; + + /* refresh counters in payload (big endian, for readability) */ + txpkt.payload[4] = (uint8_t)(cycle_count >> 8); /* MSB */ + txpkt.payload[5] = (uint8_t)(cycle_count & 0x00FF); /* LSB */ + + /* send packet */ + printf("Sending packet number %u ...", cycle_count); + i = lgw_send(txpkt); /* non-blocking scheduling of TX packet */ + if (i != LGW_HAL_SUCCESS) { + printf("ERROR\n"); + return EXIT_FAILURE; + } + + /* wait for packet to finish sending */ + do { + wait_ms(5); + lgw_status(TX_STATUS, &status_var); /* get TX status */ + } while (status_var != TX_FREE); + printf("OK\n"); + + /* wait inter-packet delay */ + wait_ms(delay); + + /* exit loop on user signals */ + if ((quit_sig == 1) || (exit_sig == 1)) { + break; + } + } + + /* clean up before leaving */ + lgw_stop(); + + printf("Exiting LoRa concentrator TX test program\n"); + return EXIT_SUCCESS; +} + +/* --- EOF ------------------------------------------------------------------ */ -- cgit v1.2.3