summaryrefslogtreecommitdiff
path: root/util_spi_stress
diff options
context:
space:
mode:
authorSylvain Miermont <smiermont@semtech.com>2014-03-28 16:58:48 +0100
committerSylvain Miermont <smiermont@semtech.com>2014-03-28 16:58:48 +0100
commitf991b0e35ad1bd3b999c70e68c518bae91bd36a6 (patch)
tree7e098ae53dc1401d88efa12de3bfc24ff405d88c /util_spi_stress
parent0e2b2cfa32767e516870a4e6a2ce0b6cce827910 (diff)
downloadlora_gateway-f991b0e35ad1bd3b999c70e68c518bae91bd36a6.tar.gz
lora_gateway-f991b0e35ad1bd3b999c70e68c518bae91bd36a6.tar.bz2
lora_gateway-f991b0e35ad1bd3b999c70e68c518bae91bd36a6.zip
v1.3.0v1.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.
Diffstat (limited to 'util_spi_stress')
-rw-r--r--util_spi_stress/Makefile57
-rw-r--r--util_spi_stress/obj/.gitkeep0
-rw-r--r--util_spi_stress/readme.md93
-rw-r--r--util_spi_stress/src/util_spi_stress.c291
4 files changed, 441 insertions, 0 deletions
diff --git a/util_spi_stress/Makefile b/util_spi_stress/Makefile
new file mode 100644
index 0000000..14cc8cb
--- /dev/null
+++ b/util_spi_stress/Makefile
@@ -0,0 +1,57 @@
+### Application-specific constants
+
+APP_NAME := util_spi_stress
+
+### 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_reg.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_spi_stress/obj/.gitkeep b/util_spi_stress/obj/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/util_spi_stress/obj/.gitkeep
diff --git a/util_spi_stress/readme.md b/util_spi_stress/readme.md
new file mode 100644
index 0000000..7848b0f
--- /dev/null
+++ b/util_spi_stress/readme.md
@@ -0,0 +1,93 @@
+ / _____) _ | |
+ ( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+ (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+LoRa concentrator SPI stress test
+==================================
+
+1. Introduction
+----------------
+
+This software is used to check the reliability of the link between the host
+platform (on which the program is run) and the LoRa concentrator register file
+that is the interface through which all interaction with the LoRa concentrator
+happens.
+
+2. Dependencies
+----------------
+
+This program only access the LoRa concentrator HAL library through its
+loragw_reg "named registers" access sub-module.
+
+It was tested with v1.3.0 of the libloragw library, and should be compatible
+with any later version of the library and the hardware, assuming the registers
+used for the tests are still present.
+
+The registers used are:
+ * LGW_VERSION
+ * LGW_IMPLICIT_PAYLOAD_LENGHT
+ * LGW_FSK_REF_PATTERN_LSB
+ * LGW_RX_DATA_BUF_ADDR
+ * LGW_RX_DATA_BUF_DATA
+
+A data buffer accessible through the 2 registers above must be implemented.
+
+3. Usage
+---------
+
+The tests run forever or until an error is detected.
+Press Ctrl+C to stop the application.
+
+When an error is detected, diagnosis information are displayed. Please refer to
+the source code for more details on what is displayed for diagnosis.
+
+All tests use pseudo-random data generated by the rand() function. The random
+generator is not seeded, and the same sequence of data will be use each time the
+program is launched.
+
+Basically, some random data is written, read back and then compared to the
+initial written data. Some "useless" read on others registers might be inserted
+to be sure that the data read back is coming from the hardware, and not from the
+internal buffer(s) of the software driver(s).
+
+Test 1 > R/W on a simple 8-bit register
+
+Test 2 > R/W on a simple 8-bit register with interstitial reads on VERSION
+
+Test 3 > R/W on a 32-bit register (short SPI bursts access)
+
+Test 4 > data buffer R/W (long SPI bursts access)
+
+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_spi_stress/src/util_spi_stress.c b/util_spi_stress/src/util_spi_stress.c
new file mode 100644
index 0000000..f86fd32
--- /dev/null
+++ b/util_spi_stress/src/util_spi_stress.c
@@ -0,0 +1,291 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ (C)2013 Semtech-Cycleo
+
+Description:
+ SPI stress test
+
+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 <stdint.h> /* C99 types */
+#include <stdbool.h> /* bool type */
+#include <stdio.h> /* printf fprintf sprintf fopen fputs */
+
+#include <signal.h> /* sigaction */
+#include <unistd.h> /* getopt access */
+#include <stdlib.h> /* rand */
+
+#include "loragw_reg.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 VERS 103
+#define READS_WHEN_ERROR 16 /* number of times a read is repeated if there is a read error */
+#define BUFF_SIZE 1024
+
+/* -------------------------------------------------------------------------- */
+/* --- 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) {
+ MSG( "Available options:\n");
+ MSG( " -h print this help\n");
+ MSG( " -t <int> specify which test you want to run (1-4)\n");
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv)
+{
+ int i;
+ int xi = 0;
+
+ /* application option */
+ int test_number = 1;
+ int cycle_number = 0;
+ int repeats_per_cycle = 1000;
+ bool error = false;
+
+ /* in/out variables */
+ int32_t test_value;
+ int32_t read_value;
+ int32_t rb1, rb2, rb3; /* interstitial readbacks, to flush buffers if needed */
+
+ /* data buffer */
+ int32_t test_addr;
+ uint8_t test_buff[BUFF_SIZE];
+ uint8_t read_buff[BUFF_SIZE];
+
+ /* parse command line options */
+ while ((i = getopt (argc, argv, "ht:")) != -1) {
+ switch (i) {
+ case 'h':
+ usage();
+ return EXIT_FAILURE;
+ break;
+
+ case 't':
+ i = sscanf(optarg, "%i", &xi);
+ if ((i != 1) || (xi < 1) || (xi > 4)) {
+ MSG("ERROR: invalid test number\n");
+ return EXIT_FAILURE;
+ } else {
+ test_number = xi;
+ }
+ break;
+
+ default:
+ MSG("ERROR: argument parsing use -h option for help\n");
+ usage();
+ return EXIT_FAILURE;
+ }
+ }
+ MSG("INFO: Starting LoRa concentrator SPI stress-test number %i\n", test_number);
+
+ /* 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);
+
+ /* start SPI link */
+ i = lgw_connect();
+ if (i != LGW_REG_SUCCESS) {
+ MSG("ERROR: lgw_connect() did not return SUCCESS");
+ return EXIT_FAILURE;
+ }
+
+ if (test_number == 1) {
+ /* single 8b register R/W stress test */
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ printf("Cycle %i > ", cycle_number);
+ for (i=0; i<repeats_per_cycle; ++i) {
+ test_value = (rand() % 256);
+ lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value);
+ lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value);
+ if (read_value != test_value) {
+ error = true;
+ break;
+ }
+ }
+ if (error) {
+ printf("error during the %ith iteration: write 0x%02X, read 0x%02X\n", i+1, test_value, read_value);
+ printf("Repeat read of target register:");
+ for (i=0; i<READS_WHEN_ERROR; ++i) {
+ lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value);
+ printf(" 0x%02X", read_value);
+ }
+ printf("\n");
+ return EXIT_FAILURE;
+ } else {
+ printf("did %i R/W on an 8 bits reg with no error\n", repeats_per_cycle);
+ ++cycle_number;
+ }
+ }
+ } else if (test_number == 2) {
+ /* single 8b register R/W with interstitial VERSION check stress test */
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ printf("Cycle %i > ", cycle_number);
+ for (i=0; i<repeats_per_cycle; ++i) {
+ test_value = (rand() % 256);
+ lgw_reg_r(LGW_VERSION, &rb1);
+ lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value);
+ lgw_reg_r(LGW_VERSION, &rb2);
+ lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value);
+ lgw_reg_r(LGW_VERSION, &rb3);
+ if ((rb1 != VERS) || (rb2 != VERS) || (rb3 != VERS) || (read_value != test_value)) {
+ error = true;
+ break;
+ }
+ }
+ if (error) {
+ printf("error during the %ith iteration: write %02X, read %02X, version (%i, %i, %i)\n", i+1, test_value, read_value, rb1, rb2, rb3);
+ printf("Repeat read of target register:");
+ for (i=0; i<READS_WHEN_ERROR; ++i) {
+ lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value);
+ printf(" 0x%02X", read_value);
+ }
+ printf("\n");
+ return EXIT_FAILURE;
+ } else {
+ printf("did %i R/W on an 8 bits reg with no error\n", repeats_per_cycle);
+ ++cycle_number;
+ }
+ }
+ } else if (test_number == 3) {
+ /* 32b register R/W stress test */
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ printf("Cycle %i > ", cycle_number);
+ for (i=0; i<repeats_per_cycle; ++i) {
+ test_value = (rand() & 0x0000FFFF);
+ test_value += (int32_t)(rand() & 0x0000FFFF) << 16;
+ lgw_reg_w(LGW_FSK_REF_PATTERN_LSB, test_value);
+ lgw_reg_r(LGW_FSK_REF_PATTERN_LSB, &read_value);
+ if (read_value != test_value) {
+ error = true;
+ break;
+ }
+ }
+ if (error) {
+ printf("error during the %ith iteration: write 0x%08X, read 0x%08X\n", i+1, test_value, read_value);
+ printf("Repeat read of target register:");
+ for (i=0; i<READS_WHEN_ERROR; ++i) {
+ lgw_reg_r(LGW_FSK_REF_PATTERN_LSB, &read_value);
+ printf(" 0x%08X", read_value);
+ }
+ printf("\n");
+ return EXIT_FAILURE;
+ } else {
+ printf("did %i R/W on a 32 bits reg with no error\n", repeats_per_cycle);
+ ++cycle_number;
+ }
+ }
+ } else if (test_number == 4) {
+ /* databuffer R/W stress test */
+ while ((quit_sig != 1) && (exit_sig != 1)) {
+ for (i=0; i<BUFF_SIZE; ++i) {
+ test_buff[i] = rand() & 0xFF;
+ }
+ printf("Cycle %i > ", cycle_number);
+ test_addr = rand() & 0xFFFF;
+ lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* write at random offset in memory */
+ lgw_reg_wb(LGW_RX_DATA_BUF_DATA, test_buff, BUFF_SIZE);
+ lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* go back to start of segment */
+ lgw_reg_rb(LGW_RX_DATA_BUF_DATA, read_buff, BUFF_SIZE);
+ for (i=0; ((i<BUFF_SIZE) && (test_buff[i] == read_buff[i])); ++i);
+ if (i != BUFF_SIZE) {
+ printf("error during the buffer comparison\n");
+ printf("Written values:\n");
+ for (i=0; i<BUFF_SIZE; ++i) {
+ printf(" %02X ", test_buff[i]);
+ if (i%16 == 15) printf("\n");
+ }
+ printf("\n");
+ printf("Read values:\n");
+ for (i=0; i<BUFF_SIZE; ++i) {
+ printf(" %02X ", read_buff[i]);
+ if (i%16 == 15) printf("\n");
+ }
+ printf("\n");
+ lgw_reg_w(LGW_RX_DATA_BUF_ADDR, test_addr); /* go back to start of segment */
+ lgw_reg_rb(LGW_RX_DATA_BUF_DATA, read_buff, BUFF_SIZE);
+ printf("Re-read values:\n");
+ for (i=0; i<BUFF_SIZE; ++i) {
+ printf(" %02X ", read_buff[i]);
+ if (i%16 == 15) printf("\n");
+ }
+ printf("\n");
+ return EXIT_FAILURE;
+ } else {
+ printf("did a %i-byte R/W on a data buffer with no error\n", BUFF_SIZE);
+ ++cycle_number;
+ }
+ }
+ } else {
+ MSG("ERROR: invalid test number");
+ usage();
+ }
+
+ /* close SPI link */
+ i = lgw_disconnect();
+ if (i != LGW_REG_SUCCESS) {
+ MSG("ERROR: lgw_disconnect() did not return SUCCESS");
+ return EXIT_FAILURE;
+ }
+
+ MSG("INFO: Exiting LoRa concentrator SPI stress-test program\n");
+ return EXIT_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */
+