summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--loragw_hal/99-libftdi.rules8
-rw-r--r--loragw_hal/INSTALL_FTDI.TXT46
-rw-r--r--loragw_hal/Makefile71
-rw-r--r--loragw_hal/README.txt32
-rw-r--r--loragw_hal/inc/loragw_hal.h2
-rw-r--r--loragw_hal/library.cfg26
-rw-r--r--loragw_hal/src/loragw_aux.c2
-rw-r--r--loragw_hal/src/loragw_hal.c35
-rw-r--r--loragw_hal/src/loragw_reg.c2
-rw-r--r--loragw_hal/src/loragw_spi.ftdi.c285
-rw-r--r--loragw_hal/src/loragw_spi.native.c (renamed from loragw_hal/src/loragw_spi.c)2
11 files changed, 472 insertions, 39 deletions
diff --git a/loragw_hal/99-libftdi.rules b/loragw_hal/99-libftdi.rules
new file mode 100644
index 0000000..8487413
--- /dev/null
+++ b/loragw_hal/99-libftdi.rules
@@ -0,0 +1,8 @@
+# FTDI Devices: FT232BM/L/Q, FT245BM/L/Q, FT232RL/Q, FT245RL/Q, VNC1L with VDPS Firmware
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0664", GROUP="plugdev"
+
+# FTDI Devices: FT2232C/D/L, FT2232HL/Q
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="0664", GROUP="plugdev"
+
+# FTDI Devices: FT4232HL/Q
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="0664", GROUP="plugdev"
diff --git a/loragw_hal/INSTALL_FTDI.TXT b/loragw_hal/INSTALL_FTDI.TXT
new file mode 100644
index 0000000..d26ad4b
--- /dev/null
+++ b/loragw_hal/INSTALL_FTDI.TXT
@@ -0,0 +1,46 @@
+# / _____) _ | |
+# ( (____ _____ ____ _| |_ _____ ____| |__
+# \____ \| ___ | (_ _) ___ |/ ___) _ \
+# _____) ) ____| | | || |_| ____( (___| | | |
+# (______/|_____)_|_|_| \__)_____)\____)_| |_|
+# ©2013 Semtech-Cycleo
+#
+# Description:
+# Installation procedure for FTDI SPI-over-USB dependencies
+
+# [STEP 1] Install libftdi
+sudo apt-get install libftdi-dev
+
+# this should install :
+# - libftdi-dev 0.19-4 (armhf)
+# - libftdil 0.19-4 (armhf)
+# - libusb-dev 2:0.1.12-20 (armhf)
+
+# [STEP 2] Download and unpack the libMPSSE 1.3
+# File must match SHA1 Checksum: 1b994a23b118f83144261e3e786c43df74a81cd5
+wget http://libmpsse.googlecode.com/files/libmpsse-1.3.tar.gz
+sha1sum libmpsse-1.3.tar.gz
+tar -xzvf libmpsse-1.3.tar.gz
+
+# Go to the src directory and install the library
+./configure --disable-python
+make
+sudo make install
+# Static and dynamic libraries compiled code is put into /usr/local/lib
+# Header file is put into /usr/local/include
+
+# On the Pcduino, you must regenerate the library cache (might some time).
+sudo ldconfig
+
+# [STEP 3] to allow non-root applications to access the FTDI device on USB
+# copy the provided 99-libftdi.rules file in /etc/udev/rules.d
+# For the nano board, only the FT2232H line is required.
+# Non-root users members of plugdev group will be able to access the device.
+
+# [STEP 4] Unpack the Lora Gateway HAL and go to its directory.
+# Configure build options in library.cfg, then build the library and examples.
+make all
+
+# [STEP 5] Connect a nanoconcentrator and run test_loragw_reg to test that
+# you have access to Lora registers.
+# Less than 50 registers of the ~300 registers should return a mismatch.
diff --git a/loragw_hal/Makefile b/loragw_hal/Makefile
index 0712c25..872952a 100644
--- a/loragw_hal/Makefile
+++ b/loragw_hal/Makefile
@@ -1,34 +1,66 @@
+# putting the configuration in a separate file
+include library.cfg
+
+# constant symbols
CC=gcc
CFLAGS=-O2 -Iinc
C99FLAGS=-O2 -std=c99 -Iinc
+
+# configuration-dependant symbols
+ifeq ($(LGW_PHY),native)
LDFLAGS=-lrt
+endif
+ifeq ($(LGW_PHY),ftdi)
+LDFLAGS=-lrt -lmpsse
+endif
+
+
+# general build targets
all: test_loragw_spi test_loragw_reg test_loragw_hal
clean:
rm -f test_*
rm -f obj/*.o
+ rm -f .conf_ok
-test_loragw_spi: obj/test_loragw_spi.o obj/loragw_spi.o
- $(CC) obj/test_loragw_spi.o obj/loragw_spi.o -o test_loragw_spi $(LDFLAGS)
+.conf_ok: library.cfg
+ @echo "*** Checking Lora gateway HAL library config ***"
+ @rm -f .conf_ok
+ifeq ($(LGW_PHY),native)
+ @echo "Selected SPI interface type: Linux native driver"
+else
+ifeq ($(LGW_PHY),ftdi)
+ @echo "Selected SPI interface type: FTDI SPI-over-USB bridge"
+else
+ $(error No SPI physical layer selected)
+endif
+endif
+ @echo "*** Config seems ok ***"
+ @touch .conf_ok
-test_loragw_reg: obj/test_loragw_reg.o obj/loragw_reg.o obj/loragw_spi.o
- $(CC) obj/test_loragw_reg.o obj/loragw_reg.o obj/loragw_spi.o -o test_loragw_reg $(LDFLAGS)
-
-test_loragw_hal: obj/test_loragw_hal.o obj/loragw_hal.o obj/loragw_reg.o obj/loragw_spi.o obj/loragw_aux.o
- $(CC) obj/test_loragw_hal.o obj/loragw_hal.o obj/loragw_reg.o obj/loragw_spi.o obj/loragw_aux.o -o test_loragw_hal $(LDFLAGS)
-obj/loragw_aux.o: src/loragw_aux.c inc/loragw_aux.h
- $(CC) -c $(CFLAGS) src/loragw_aux.c -o obj/loragw_aux.o
+# library module target
+
+obj/loragw_aux.o: .conf_ok src/loragw_aux.c inc/loragw_aux.h
+ $(CC) -c $(CFLAGS) src/loragw_aux.c -o obj/loragw_aux.o $(FLAG_AUX)
-obj/loragw_spi.o: src/loragw_spi.c inc/loragw_spi.h
- $(CC) -c $(C99FLAGS) src/loragw_spi.c -o obj/loragw_spi.o
+obj/loragw_spi.o: .conf_ok src/loragw_spi.native.c src/loragw_spi.ftdi.c inc/loragw_spi.h
+ifeq ($(LGW_PHY),native)
+ $(CC) -c $(C99FLAGS) src/loragw_spi.native.c -o obj/loragw_spi.o $(FLAG_SPI)
+endif
+ifeq ($(LGW_PHY),ftdi)
+ $(CC) -c $(C99FLAGS) src/loragw_spi.ftdi.c -o obj/loragw_spi.o $(FLAG_SPI)
+endif
-obj/loragw_reg.o: src/loragw_reg.c inc/loragw_reg.h inc/loragw_spi.h
- $(CC) -c $(C99FLAGS) src/loragw_reg.c -o obj/loragw_reg.o
+obj/loragw_reg.o: .conf_ok src/loragw_reg.c inc/loragw_reg.h inc/loragw_spi.h
+ $(CC) -c $(C99FLAGS) src/loragw_reg.c -o obj/loragw_reg.o $(FLAG_REG)
-obj/loragw_hal.o: src/loragw_hal.c src/arb_fw.var src/agc_fw.var inc/loragw_hal.h inc/loragw_reg.h inc/loragw_spi.h inc/loragw_aux.h
- $(CC) -c $(C99FLAGS) src/loragw_hal.c -o obj/loragw_hal.o
+obj/loragw_hal.o: .conf_ok src/loragw_hal.c src/arb_fw.var src/agc_fw.var inc/loragw_hal.h inc/loragw_reg.h inc/loragw_spi.h inc/loragw_aux.h
+ $(CC) -c $(C99FLAGS) src/loragw_hal.c -o obj/loragw_hal.o $(FLAG_HAL)
+
+
+# test programs
obj/test_loragw_spi.o: test/test_loragw_spi.c inc/loragw_spi.h
$(CC) -c $(C99FLAGS) -Iinc test/test_loragw_spi.c -o obj/test_loragw_spi.o
@@ -39,3 +71,12 @@ obj/test_loragw_reg.o: test/test_loragw_reg.c inc/loragw_reg.h
obj/test_loragw_hal.o: test/test_loragw_hal.c inc/loragw_hal.h inc/loragw_aux.h
$(CC) -c $(C99FLAGS) test/test_loragw_hal.c -o obj/test_loragw_hal.o
+test_loragw_spi: .conf_ok obj/test_loragw_spi.o obj/loragw_spi.o
+ $(CC) obj/test_loragw_spi.o obj/loragw_spi.o -o test_loragw_spi $(LDFLAGS)
+
+test_loragw_reg: .conf_ok obj/test_loragw_reg.o obj/loragw_reg.o obj/loragw_spi.o
+ $(CC) obj/test_loragw_reg.o obj/loragw_reg.o obj/loragw_spi.o -o test_loragw_reg $(LDFLAGS)
+
+test_loragw_hal: .conf_ok obj/test_loragw_hal.o obj/loragw_hal.o obj/loragw_reg.o obj/loragw_spi.o obj/loragw_aux.o
+ $(CC) obj/test_loragw_hal.o obj/loragw_hal.o obj/loragw_reg.o obj/loragw_spi.o obj/loragw_aux.o -o test_loragw_hal $(LDFLAGS)
+
diff --git a/loragw_hal/README.txt b/loragw_hal/README.txt
index 15034ff..58e7fbe 100644
--- a/loragw_hal/README.txt
+++ b/loragw_hal/README.txt
@@ -1,5 +1,14 @@
-Lora Gateway HAL
-================
++===============================================+
+| / _____) _ | | |
+| ( (____ _____ ____ _| |_ _____ ____| |__ |
+| \____ \| ___ | (_ _) ___ |/ ___) _ \ |
+| _____) ) ____| | | || |_| ____( (___| | | | |
+| (______/|_____)_|_|_| \__)_____)\____)_| |_| |
+| ©2013 Semtech-Cycleo |
+| |
+| Description: |
+| Lora Gateway HAL documentation |
++===============================================+
1. Introduction
---------------
@@ -119,7 +128,18 @@ accuracy pause.
For embedded platforms, the function could be rewritten using hardware times.
All modules use the fprintf(stderr,...) function to display debug diagnostic
-messages if the DEBUG flag is defined (eg. for GCC, add the -DDEBUG flag).
+messages if the DEBUG_xxx is set to 1 in library.cfg
+
+Depending on config, SPI module needs LibMPSSE to access the FTDI SPI-over-USB
+bridge. Please go to that URL to download that library:
+http://code.google.com/p/libmpsse/
+
+The code was tested with version 1.3 of LibMPSSE:
+http://libmpsse.googlecode.com/files/libmpsse-1.3.tar.gz
+SHA1 Checksum: 1b994a23b118f83144261e3e786c43df74a81cd5
+
+That library has some dependencies itself, please read the installation
+instructions.
4. Hardware dependencies
@@ -137,9 +157,11 @@ are platform-dependant.
The functions must be rewritten depending on the SPI bridge you use:
* SPI master matched to the Linux SPI device driver (provided)
-* SPI over USB using FTDI components (not provided)
+* SPI over USB using FTDI components (provided)
* native SPI using a microcontroller peripheral (not provided)
+Edit library.cfg to chose which SPI physical interface you want to use.
+
You can use the test program test_loragw_spi to check with a logic analyser
that the SPI communication is working
@@ -170,7 +192,7 @@ loop {
<stop the gateway>
To debug your application, it might help to compile the loragw_hal function
-with the DEBUG flag defined.
+with the debug messages activated (set DEBUG_HAL=1 in library.cfg).
It then send a lot of details, including detailed error messages to *stderr*.
diff --git a/loragw_hal/inc/loragw_hal.h b/loragw_hal/inc/loragw_hal.h
index eeccaf2..bc28741 100644
--- a/loragw_hal/inc/loragw_hal.h
+++ b/loragw_hal/inc/loragw_hal.h
@@ -43,7 +43,6 @@ Description:
#define LGW_PKT_FIFO_SIZE 8
#define LGW_DATABUFF_SIZE 1024
-#define LGW_RADIO_BW 500000 /* bandwidth of the radio */
#define LGW_REF_BW 125000 /* typical bandwidth of data channel */
/*
@@ -58,6 +57,7 @@ F_register(24bit) = F_rf (Hz) / F_step(Hz)
/* to use those parameters, declare a local constant, and use 'rf_chain' as index */
#define LGW_RF_RX_LOWFREQ {863000000, 863000000}
#define LGW_RF_RX_UPFREQ {870000000, 870000000}
+#define LGW_RF_RX_BANDWIDTH {800000, 800000} /* bandwidth of the radios */
#define LGW_RF_TX_LOWFREQ {863000000, 863000000}
#define LGW_RF_TX_UPFREQ {870000000, 870000000}
diff --git a/loragw_hal/library.cfg b/loragw_hal/library.cfg
new file mode 100644
index 0000000..ac24416
--- /dev/null
+++ b/loragw_hal/library.cfg
@@ -0,0 +1,26 @@
+# / _____) _ | |
+# ( (____ _____ ____ _| |_ _____ ____| |__
+# \____ \| ___ | (_ _) ___ |/ ___) _ \
+# _____) ) ____| | | || |_| ____( (___| | | |
+# (______/|_____)_|_|_| \__)_____)\____)_| |_|
+# ©2013 Semtech-Cycleo
+#
+# Description:
+# Lora gateway Hardware Abstraction Layer library configuration
+
+
+# Set the DEBUG_* to 1 to activate debug mode in individual modules.
+# Warning: that makes the module *very verbose*, do not use for production
+FLAG_AUX= -D DEBUG_AUX=0
+FLAG_SPI= -D DEBUG_SPI=0
+FLAG_REG= -D DEBUG_REG=0
+FLAG_HAL= -D DEBUG_HAL=0
+
+# The flags bellow define which physical link to the nano board will be used
+# Pick one and comment the other(s)
+
+# Pcduino native SPI (Linux device in /dev)
+LGW_PHY= native
+
+# FTDI SPI-over-USB bridge
+#LGW_PHY= ftdi
diff --git a/loragw_hal/src/loragw_aux.c b/loragw_hal/src/loragw_aux.c
index 9adafe3..1c7e354 100644
--- a/loragw_hal/src/loragw_aux.c
+++ b/loragw_hal/src/loragw_aux.c
@@ -20,7 +20,7 @@ Description:
/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */
-#ifdef DEBUG
+#if DEBUG_AUX == 1
#define DEBUG_MSG(str) fprintf(stderr, str)
#define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
#else
diff --git a/loragw_hal/src/loragw_hal.c b/loragw_hal/src/loragw_hal.c
index fc9e293..1738916 100644
--- a/loragw_hal/src/loragw_hal.c
+++ b/loragw_hal/src/loragw_hal.c
@@ -29,7 +29,7 @@ Description:
/* --- PRIVATE MACROS ------------------------------------------------------- */
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#ifdef DEBUG
+#if DEBUG_HAL == 1
#define DEBUG_MSG(str) fprintf(stderr, str)
#define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
#define DEBUG_ARRAY(a,b,c) for(a=0;a<b;++a) fprintf(stderr,"%x.",c[a]);fprintf(stderr,"end\n")
@@ -54,6 +54,7 @@ const uint8_t ifmod_config[LGW_IF_CHAIN_NB] = LGW_IFMODEM_CONFIG; /* define hard
const uint32_t rf_rx_lowfreq[LGW_RF_CHAIN_NB] = LGW_RF_RX_LOWFREQ;
const uint32_t rf_rx_upfreq[LGW_RF_CHAIN_NB] = LGW_RF_RX_UPFREQ;
+const uint32_t rf_rx_bandwidth[LGW_RF_CHAIN_NB] = LGW_RF_RX_BANDWIDTH;
const uint32_t rf_tx_lowfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_LOWFREQ;
const uint32_t rf_tx_upfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_UPFREQ;
@@ -73,8 +74,8 @@ const uint32_t rf_tx_upfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_UPFREQ;
#define SX1257_RX_ADC_TRIM 6 /* 0 to 7, 6 for 32MHz ref, 5 for 36MHz ref */
#define SX1257_RXBB_BW 2
-#define RSSI_OFFSET_LORA_MULTI -100.0 // TODO: need to find proper value with calibration
-#define RSSI_OFFSET_LORA_STD -100.0 // TODO: need to find proper value with calibration
+#define RSSI_OFFSET_LORA_MULTI -127.0 /* calibrated value */
+#define RSSI_OFFSET_LORA_STD 0.0 /* RSSI not working properly on that IF channel */
#define TX_METADATA_NB 16
#define RX_METADATA_NB 16
@@ -447,10 +448,14 @@ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) {
if (ifmod_config[if_chain] == IF_UNDEFINED) {
DEBUG_PRINTF("ERROR: IF CHAIN %d NOT CONFIGURABLE\n", if_chain);
}
- if ((conf.freq_hz + LGW_REF_BW/2) > LGW_RADIO_BW/2) {
+ if (conf.rf_chain >= LGW_RF_CHAIN_NB) {
+ DEBUG_MSG("ERROR: INVALID RF_CHAIN TO ASSOCIATE WITH A LORA_STD IF CHAIN\n");
+ return LGW_HAL_ERROR;
+ }
+ if ((conf.freq_hz + LGW_REF_BW/2) > ((int32_t)rf_rx_bandwidth[conf.rf_chain] / 2)) {
DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO HIGH\n", conf.freq_hz);
return LGW_HAL_ERROR;
- } else if ((conf.freq_hz - LGW_REF_BW/2) < -LGW_RADIO_BW/2) {
+ } else if ((conf.freq_hz - LGW_REF_BW/2) < -((int32_t)rf_rx_bandwidth[conf.rf_chain] / 2)) {
DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO LOW\n", conf.freq_hz);
return LGW_HAL_ERROR;
}
@@ -495,10 +500,6 @@ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) {
break;
case IF_LORA_MULTI:
- if (conf.rf_chain >= LGW_RF_CHAIN_NB) {
- DEBUG_MSG("ERROR: INVALID RF_CHAIN TO ASSOCIATE WITH A LORA_STD IF CHAIN\n");
- return LGW_HAL_ERROR;
- }
/* fill default parameters if needed */
if (conf.datarate == 0) {
conf.datarate = DR_LORA_MULTI;
@@ -755,10 +756,10 @@ int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) {
p->snr_min = ((float)((int8_t)buff[s+3]))/4;
p->snr_max = ((float)((int8_t)buff[s+4]))/4;
if (ifmod == IF_LORA_MULTI) {
- p->rssi = RSSI_OFFSET_LORA_MULTI + (float)buff[s+5]; //TODO: check formula
+ p->rssi = RSSI_OFFSET_LORA_MULTI + (float)buff[s+5];
p->bandwidth = BW_125KHZ; /* fixed in hardware */
} else {
- p->rssi = RSSI_OFFSET_LORA_STD + (float)buff[s+5]; //TODO: check formula, might depend on bandwidth
+ p->rssi = RSSI_OFFSET_LORA_STD + (float)buff[s+5];
p->bandwidth = lora_rx_bw; /* get the parameter from the config variable */
}
switch ((buff[s+1] >> 4) & 0x0F) {
@@ -872,6 +873,11 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) {
return LGW_HAL_ERROR;
}
+ /* reset TX command flags */
+ lgw_reg_w(LGW_TX_TRIG_IMMEDIATE, 0);
+ lgw_reg_w(LGW_TX_TRIG_DELAYED, 0);
+ lgw_reg_w(LGW_TX_TRIG_GPS, 0);
+
/* metadata 0 to 2, TX PLL frequency */
part_int = pkt_data.freq_hz / LGW_SX1257_DENOMINATOR; /* integer part, gives the MSB and the middle byte */
part_frac = ((pkt_data.freq_hz % LGW_SX1257_DENOMINATOR) << 8) / LGW_SX1257_DENOMINATOR; /* fractional part, gives LSB */
@@ -962,21 +968,20 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) {
/* send data */
switch(pkt_data.tx_mode) {
case IMMEDIATE:
- lgw_reg_w(LGW_TX_TRIG_IMMEDIATE, 0);
lgw_reg_w(LGW_TX_TRIG_IMMEDIATE, 1);
break;
case TIMESTAMPED:
- lgw_reg_w(LGW_TX_TRIG_DELAYED, 0);
lgw_reg_w(LGW_TX_TRIG_DELAYED, 1);
break;
case ON_GPS:
- lgw_reg_w(LGW_TX_TRIG_GPS, 0);
lgw_reg_w(LGW_TX_TRIG_GPS, 1);
break;
- default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.tx_mode);
+ default:
+ DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.tx_mode);
+ return LGW_HAL_ERROR;
}
return LGW_HAL_SUCCESS;
diff --git a/loragw_hal/src/loragw_reg.c b/loragw_hal/src/loragw_reg.c
index ab5a922..716c6c0 100644
--- a/loragw_hal/src/loragw_reg.c
+++ b/loragw_hal/src/loragw_reg.c
@@ -28,7 +28,7 @@ Description:
/* --- PRIVATE MACROS ------------------------------------------------------- */
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#ifdef DEBUG
+#if DEBUG_REG == 1
#define DEBUG_MSG(str) fprintf(stderr, str)
#define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
#define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;}
diff --git a/loragw_hal/src/loragw_spi.ftdi.c b/loragw_hal/src/loragw_spi.ftdi.c
new file mode 100644
index 0000000..7b71901
--- /dev/null
+++ b/loragw_hal/src/loragw_spi.ftdi.c
@@ -0,0 +1,285 @@
+/*
+ / _____) _ | |
+( (____ _____ ____ _| |_ _____ ____| |__
+ \____ \| ___ | (_ _) ___ |/ ___) _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+ ©2013 Semtech-Cycleo
+
+Description:
+ Host specific functions to address the LoRa™ gateway registers through a
+ SPI interface.
+ Single-byte read/write and burst read/write.
+ Does not handle pagination.
+ Could be used with multiple SPI ports in parallel (explicit file descriptor)
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h> /* C99 types */
+#include <stdio.h> /* printf fprintf */
+#include <stdlib.h> /* malloc free */
+#include <string.h> /* memcpy */
+
+#include <mpsse.h>
+
+#include "loragw_spi.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_SPI == 1
+ #define DEBUG_MSG(str) fprintf(stderr, str)
+ #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+ #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_SPI_ERROR;}
+#else
+ #define DEBUG_MSG(str)
+ #define DEBUG_PRINTF(fmt, args...)
+ #define CHECK_NULL(a) if(a==NULL){return LGW_SPI_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define READ_ACCESS 0x00
+#define WRITE_ACCESS 0x80
+
+/* parameters for a FT2232H */
+#define VID 0x0403
+#define PID 0x6010
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+/* SPI initialization and configuration */
+int lgw_spi_open(void **spi_target_ptr) {
+ struct mpsse_context *mpsse = NULL;
+
+ /* check input variables */
+ CHECK_NULL(spi_target_ptr); /* cannot be null, must point on a void pointer (*spi_target_ptr can be null) */
+
+ /* try to open the first available FTDI device matching VID/PID parameters */
+ mpsse = OpenIndex(VID,PID,SPI0, SIX_MHZ, MSB, IFACE_A, NULL, NULL, 0);
+ if (mpsse == NULL) {
+ DEBUG_MSG("ERROR: MPSSE OPEN FUNCTION RETURNED NULL\n");
+ return LGW_SPI_ERROR;
+ }
+ if (mpsse->open != 1) {
+ DEBUG_MSG("ERROR: MPSSE OPEN FUNCTION FAILED\n");
+ return LGW_SPI_ERROR;
+ }
+
+ 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());
+ *spi_target_ptr = (void *)mpsse;
+ return LGW_SPI_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* SPI release */
+int lgw_spi_close(void *spi_target) {
+ struct mpsse_context *mpsse = spi_target;
+
+ /* check input variables */
+ CHECK_NULL(spi_target);
+
+ Close(mpsse);
+
+ /* close return no status, assume success (0_o) */
+ return LGW_SPI_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Simple write */
+/* transaction time: .6 to 1 ms typically */
+int lgw_spi_w(void *spi_target, uint8_t address, uint8_t data) {
+ struct mpsse_context *mpsse = spi_target;
+ uint8_t out_buf[2];
+ int a, b, c;
+
+ /* check input variables */
+ CHECK_NULL(spi_target);
+ if ((address & 0x80) != 0) {
+ DEBUG_MSG("WARNING: SPI address > 127\n");
+ }
+
+ /* prepare frame to be sent */
+ out_buf[0] = WRITE_ACCESS | (address & 0x7F);
+ out_buf[1] = data;
+
+ /* MPSSE transaction */
+ a = Start(mpsse);
+ b = FastWrite(mpsse, (char *)out_buf, 2);
+ c = Stop(mpsse);
+
+ /* determine return code */
+ if ((a != MPSSE_OK) || (b != MPSSE_OK) || (c != MPSSE_OK)) {
+ DEBUG_MSG("ERROR: SPI WRITE FAILURE\n");
+ return LGW_SPI_ERROR;
+ } else {
+ DEBUG_MSG("Note: SPI write success\n");
+ return LGW_SPI_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Simple read (using Transfer function) */
+/* transaction time: 1.1 to 2 ms typically */
+int lgw_spi_r(void *spi_target, uint8_t address, uint8_t *data) {
+ struct mpsse_context *mpsse = spi_target;
+ uint8_t out_buf[2];
+ uint8_t *in_buf = NULL;
+ int a, b;
+
+ /* check input variables */
+ CHECK_NULL(spi_target);
+ if ((address & 0x80) != 0) {
+ DEBUG_MSG("WARNING: SPI address > 127\n");
+ }
+ CHECK_NULL(data);
+
+ /* prepare frame to be sent */
+ out_buf[0] = READ_ACCESS | (address & 0x7F);
+ out_buf[1] = 0x00;
+
+ /* MPSSE transaction */
+ a = Start(mpsse);
+ in_buf = (uint8_t *)Transfer(mpsse, (char *)out_buf, 2);
+ b = Stop(mpsse);
+
+ /* determine return code */
+ if ((in_buf == NULL) || (a != MPSSE_OK) || (b != MPSSE_OK)) {
+ DEBUG_MSG("ERROR: SPI READ FAILURE\n");
+ if (in_buf != NULL) {
+ free(in_buf);
+ }
+ return LGW_SPI_ERROR;
+ } else {
+ DEBUG_MSG("Note: SPI read success\n");
+ *data = in_buf[1];
+ free(in_buf);
+ return LGW_SPI_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Burst (multiple-byte) write */
+/* transaction time: 3.7ms for 2500 data bytes @6MHz, 1kB chunks */
+/* transaction time: 0.5ms for 16 data bytes @6MHz, 1kB chunks */
+int lgw_spi_wb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) {
+ struct mpsse_context *mpsse = spi_target;
+ uint8_t command;
+ uint8_t *out_buf = NULL;
+ int size_to_do, buf_size, chunk_size, offset;
+ int a, b, c;
+ int i;
+
+ /* check input parameters */
+ CHECK_NULL(spi_target);
+ if ((address & 0x80) != 0) {
+ DEBUG_MSG("WARNING: SPI address > 127\n");
+ }
+ CHECK_NULL(data);
+ if (size == 0) {
+ DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n");
+ return LGW_SPI_ERROR;
+ }
+
+ /* prepare command byte */
+ command = WRITE_ACCESS | (address & 0x7F);
+ size_to_do = size + 1; /* add a byte for the address */
+
+ /* allocate data buffer */
+ buf_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK;
+ out_buf = malloc(buf_size);
+ if (out_buf == NULL) {
+ DEBUG_MSG("ERROR: MALLOC FAIL\n");
+ return LGW_SPI_ERROR;
+ }
+
+ /* start MPSSE transaction */
+ a = Start(mpsse);
+ for (i=0; size_to_do > 0; ++i) {
+ chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK;
+ if (i == 0) {
+ /* first chunk, need to append the address */
+ out_buf[0] = command;
+ memcpy(out_buf+1, data, chunk_size-1);
+ } else {
+ /* following chunks, just copy the data */
+ offset = (i * LGW_BURST_CHUNK) - 1;
+ memcpy(out_buf, data + offset, chunk_size);
+ }
+ b = FastWrite(mpsse, (char *)out_buf, chunk_size);
+ size_to_do -= chunk_size; /* subtract the quantity of data already transferred */
+ }
+ c = Stop(mpsse);
+
+ /* deallocate data buffer */
+ free(out_buf);
+
+ /* determine return code (only the last FastWrite is checked) */
+ if ((a != MPSSE_OK) || (b != MPSSE_OK) || (c != MPSSE_OK)) {
+ DEBUG_MSG("ERROR: SPI BURST WRITE FAILURE\n");
+ return LGW_SPI_ERROR;
+ } else {
+ DEBUG_MSG("Note: SPI burst write success\n");
+ return LGW_SPI_SUCCESS;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Burst (multiple-byte) read (using FastWrite & FastRead functions) */
+/* transaction time: 7-12ms for 2500 data bytes @6MHz, 1kB chunks */
+/* transaction time: 2ms for 16 data bytes @6MHz, 1kB chunks */
+int lgw_spi_rb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) {
+ struct mpsse_context *mpsse = spi_target;
+ uint8_t command;
+ int size_to_do, chunk_size, offset;
+ int a, b, c, d;
+ int i;
+
+ /* check input parameters */
+ CHECK_NULL(spi_target);
+ if ((address & 0x80) != 0) {
+ DEBUG_MSG("WARNING: SPI address > 127\n");
+ }
+ CHECK_NULL(data);
+ if (size == 0) {
+ DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n");
+ return LGW_SPI_ERROR;
+ }
+
+ /* prepare command byte */
+ command = READ_ACCESS | (address & 0x7F);
+ size_to_do = size;
+
+ /* start MPSSE transaction */
+ a = Start(mpsse);
+ b = FastWrite(mpsse, (char *)&command, 1);
+ for (i=0; size_to_do > 0; ++i) {
+ chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK;
+ offset = i * LGW_BURST_CHUNK;
+ c = FastRead(mpsse, (char *)(data + offset), chunk_size);
+ size_to_do -= chunk_size; /* subtract the quantity of data already transferred */
+ }
+ d = Stop(mpsse);
+
+ /* determine return code (only the last FastRead is checked) */
+ if ((a != MPSSE_OK) || (b != MPSSE_OK) || (c != MPSSE_OK) || (d != MPSSE_OK)) {
+ DEBUG_MSG("ERROR: SPI BURST READ FAILURE\n");
+ return LGW_SPI_ERROR;
+ } else {
+ DEBUG_MSG("Note: SPI burst read success\n");
+ return LGW_SPI_SUCCESS;
+ }
+}
+
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/loragw_hal/src/loragw_spi.c b/loragw_hal/src/loragw_spi.native.c
index d6e3eb0..f5f0701 100644
--- a/loragw_hal/src/loragw_spi.c
+++ b/loragw_hal/src/loragw_spi.native.c
@@ -34,7 +34,7 @@ Description:
/* --- PRIVATE MACROS ------------------------------------------------------- */
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#ifdef DEBUG
+#if DEBUG_SPI == 1
#define DEBUG_MSG(str) fprintf(stderr, str)
#define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
#define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_SPI_ERROR;}