From 33ade9eb698f594e95076a5e4056a70163f14278 Mon Sep 17 00:00:00 2001 From: Sylvain Miermont Date: Mon, 2 Sep 2013 16:13:41 +0200 Subject: Beta 4 - now supports 'native' Linux /dev/spi* interface and SPI-over-USB using FTDI bridge through libmpsse - Flexible build system, with library.cfg file to set Makefile options - removed 500 kHz bandwidth limitation on radios, pushed it to the nominal 800kHz usable bandwidth - RSSI calibrated fo Lora multi-datarate channels --- loragw_hal/99-libftdi.rules | 8 + loragw_hal/INSTALL_FTDI.TXT | 46 +++++ loragw_hal/Makefile | 71 ++++++-- loragw_hal/README.txt | 32 +++- loragw_hal/inc/loragw_hal.h | 2 +- loragw_hal/library.cfg | 26 +++ loragw_hal/src/loragw_aux.c | 2 +- loragw_hal/src/loragw_hal.c | 35 ++-- loragw_hal/src/loragw_reg.c | 2 +- loragw_hal/src/loragw_spi.c | 346 ------------------------------------- loragw_hal/src/loragw_spi.ftdi.c | 285 ++++++++++++++++++++++++++++++ loragw_hal/src/loragw_spi.native.c | 346 +++++++++++++++++++++++++++++++++++++ 12 files changed, 817 insertions(+), 384 deletions(-) create mode 100644 loragw_hal/99-libftdi.rules create mode 100644 loragw_hal/INSTALL_FTDI.TXT create mode 100644 loragw_hal/library.cfg delete mode 100644 loragw_hal/src/loragw_spi.c create mode 100644 loragw_hal/src/loragw_spi.ftdi.c create mode 100644 loragw_hal/src/loragw_spi.native.c 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 { 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 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.c b/loragw_hal/src/loragw_spi.c deleted file mode 100644 index d6e3eb0..0000000 --- a/loragw_hal/src/loragw_spi.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - ©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 /* C99 types */ -#include /* printf fprintf */ -#include /* malloc free */ -#include /* lseek, close */ -#include /* open */ -#include /* memset */ - -#include -#include - -#include "loragw_spi.h" - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE MACROS ------------------------------------------------------- */ - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#ifdef DEBUG - #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 -#define SPI_SPEED 8000000 -#define SPI_DEV_PATH "/dev/spidev0.0" - -/* -------------------------------------------------------------------------- */ -/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ - -/* SPI initialization and configuration */ -int lgw_spi_open(void **spi_target_ptr) { - int *spi_device = NULL; - int dev; - int a,b,c; - int i; - - /* check input variables */ - CHECK_NULL(spi_target_ptr); /* cannot be null, must point on a void pointer (*spi_target_ptr can be null) */ - - /* allocate memory for the device descriptor */ - spi_device = malloc(sizeof(int)); - if (spi_device == NULL) { - DEBUG_MSG("ERROR: MALLOC FAIL\n"); - return LGW_SPI_ERROR; - } - - /* open SPI device */ - dev = open(SPI_DEV_PATH, O_RDWR); - if (dev < 0) { - DEBUG_MSG("SPI port fail to open\n"); - return LGW_SPI_ERROR; - } - - /* setting SPI mode to 'mode 0' */ - i = SPI_MODE_0; - a = ioctl(dev, SPI_IOC_WR_MODE, &i); - b = ioctl(dev, SPI_IOC_RD_MODE, &i); - if ((a < 0) || (b < 0)) { - DEBUG_MSG("ERROR: SPI PORT FAIL TO SET IN MODE 0\n"); - close(dev); - free(spi_device); - return LGW_SPI_ERROR; - } - - /* setting SPI max clk (in Hz) */ - i = SPI_SPEED; - a = ioctl(dev, SPI_IOC_WR_MAX_SPEED_HZ, &i); - b = ioctl(dev, SPI_IOC_RD_MAX_SPEED_HZ, &i); - if ((a < 0) || (b < 0)) { - DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MAX SPEED\n"); - close(dev); - free(spi_device); - return LGW_SPI_ERROR; - } - - /* setting SPI to MSB first */ - i = 0; - a = ioctl(dev, SPI_IOC_WR_LSB_FIRST, &i); - b = ioctl(dev, SPI_IOC_RD_LSB_FIRST, &i); - if ((a < 0) || (b < 0)) { - DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MSB FIRST\n"); - close(dev); - free(spi_device); - return LGW_SPI_ERROR; - } - - /* setting SPI to 8 bits per word */ - i = 0; - a = ioctl(dev, SPI_IOC_WR_BITS_PER_WORD, &i); - b = ioctl(dev, SPI_IOC_RD_BITS_PER_WORD, &i); - if ((a < 0) || (b < 0)) { - DEBUG_MSG("ERROR: SPI PORT FAIL TO SET 8 BITS-PER-WORD\n"); - close(dev); - return LGW_SPI_ERROR; - } - - *spi_device = dev; - *spi_target_ptr = (void *)spi_device; - DEBUG_MSG("Note: SPI port opened and configured ok\n"); - return LGW_SPI_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -/* SPI release */ -int lgw_spi_close(void *spi_target) { - int spi_device; - int a; - - /* check input variables */ - CHECK_NULL(spi_target); - - /* close file & deallocate file descriptor */ - spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ - a = close(spi_device); - free(spi_target); - - /* determine return code */ - if (a < 0) { - DEBUG_MSG("ERROR: SPI PORT FAILED TO CLOSE\n"); - return LGW_SPI_ERROR; - } else { - DEBUG_MSG("Note: SPI port closed\n"); - return LGW_SPI_SUCCESS; - } -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -/* Simple write */ -int lgw_spi_w(void *spi_target, uint8_t address, uint8_t data) { - int spi_device; - uint8_t out_buf[2]; - struct spi_ioc_transfer k; - int a; - - /* check input variables */ - CHECK_NULL(spi_target); - if ((address & 0x80) != 0) { - DEBUG_MSG("WARNING: SPI address > 127\n"); - } - - spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ - - /* prepare frame to be sent */ - out_buf[0] = WRITE_ACCESS | (address & 0x7F); - out_buf[1] = data; - - /* I/O transaction */ - memset(&k, 0, sizeof(k)); /* clear k */ - k.tx_buf = (unsigned long) out_buf; - k.len = ARRAY_SIZE(out_buf); - k.speed_hz = SPI_SPEED; - k.cs_change = 1; - k.bits_per_word = 8; - a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); - - /* determine return code */ - if (a != 2) { - 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 */ -int lgw_spi_r(void *spi_target, uint8_t address, uint8_t *data) { - int spi_device; - uint8_t out_buf[2]; - uint8_t in_buf[ARRAY_SIZE(out_buf)]; - struct spi_ioc_transfer k; - int a; - - /* check input variables */ - CHECK_NULL(spi_target); - if ((address & 0x80) != 0) { - DEBUG_MSG("WARNING: SPI address > 127\n"); - } - CHECK_NULL(data); - - spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ - - /* prepare frame to be sent */ - out_buf[0] = READ_ACCESS | (address & 0x7F); - out_buf[1] = 0x00; - - /* I/O transaction */ - memset(&k, 0, sizeof(k)); /* clear k */ - k.tx_buf = (unsigned long) out_buf; - k.rx_buf = (unsigned long) in_buf; - k.len = ARRAY_SIZE(out_buf); - k.cs_change = 1; - a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); - - /* determine return code */ - if (a != 2) { - DEBUG_MSG("ERROR: SPI READ FAILURE\n"); - return LGW_SPI_ERROR; - } else { - DEBUG_MSG("Note: SPI read success\n"); - *data = in_buf[1]; - return LGW_SPI_SUCCESS; - } -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -/* Burst (multiple-byte) write */ -int lgw_spi_wb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) { - int spi_device; - uint8_t command; - struct spi_ioc_transfer k[2]; - int size_to_do, chunk_size, offset; - int byte_transfered = 0; - 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; - } - - spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ - - /* prepare command byte */ - command = WRITE_ACCESS | (address & 0x7F); - size_to_do = size; - - /* I/O transaction */ - memset(&k, 0, sizeof(k)); /* clear k */ - k[0].tx_buf = (unsigned long) &command; - k[0].len = 1; - k[0].cs_change = 0; - k[1].cs_change = 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; - k[1].tx_buf = (unsigned long)(data + offset); - k[1].len = chunk_size; - byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - 1 ); - DEBUG_PRINTF("BURST WRITE: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered); - size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ - } - - /* determine return code */ - if (byte_transfered != size) { - 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 */ -int lgw_spi_rb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) { - int spi_device; - uint8_t command; - struct spi_ioc_transfer k[2]; - int size_to_do, chunk_size, offset; - int byte_transfered = 0; - 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; - } - - spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ - - /* prepare command byte */ - command = READ_ACCESS | (address & 0x7F); - size_to_do = size; - - /* I/O transaction */ - memset(&k, 0, sizeof(k)); /* clear k */ - k[0].tx_buf = (unsigned long) &command; - k[0].len = 1; - k[0].cs_change = 0; - k[1].cs_change = 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; - k[1].rx_buf = (unsigned long)(data + offset); - k[1].len = chunk_size; - byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - 1 ); - DEBUG_PRINTF("BURST READ: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered); - size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ - } - - /* determine return code */ - if (byte_transfered != size) { - 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.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 /* C99 types */ +#include /* printf fprintf */ +#include /* malloc free */ +#include /* memcpy */ + +#include + +#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.native.c b/loragw_hal/src/loragw_spi.native.c new file mode 100644 index 0000000..f5f0701 --- /dev/null +++ b/loragw_hal/src/loragw_spi.native.c @@ -0,0 +1,346 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + ©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 /* C99 types */ +#include /* printf fprintf */ +#include /* malloc free */ +#include /* lseek, close */ +#include /* open */ +#include /* memset */ + +#include +#include + +#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 +#define SPI_SPEED 8000000 +#define SPI_DEV_PATH "/dev/spidev0.0" + +/* -------------------------------------------------------------------------- */ +/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ + +/* SPI initialization and configuration */ +int lgw_spi_open(void **spi_target_ptr) { + int *spi_device = NULL; + int dev; + int a,b,c; + int i; + + /* check input variables */ + CHECK_NULL(spi_target_ptr); /* cannot be null, must point on a void pointer (*spi_target_ptr can be null) */ + + /* allocate memory for the device descriptor */ + spi_device = malloc(sizeof(int)); + if (spi_device == NULL) { + DEBUG_MSG("ERROR: MALLOC FAIL\n"); + return LGW_SPI_ERROR; + } + + /* open SPI device */ + dev = open(SPI_DEV_PATH, O_RDWR); + if (dev < 0) { + DEBUG_MSG("SPI port fail to open\n"); + return LGW_SPI_ERROR; + } + + /* setting SPI mode to 'mode 0' */ + i = SPI_MODE_0; + a = ioctl(dev, SPI_IOC_WR_MODE, &i); + b = ioctl(dev, SPI_IOC_RD_MODE, &i); + if ((a < 0) || (b < 0)) { + DEBUG_MSG("ERROR: SPI PORT FAIL TO SET IN MODE 0\n"); + close(dev); + free(spi_device); + return LGW_SPI_ERROR; + } + + /* setting SPI max clk (in Hz) */ + i = SPI_SPEED; + a = ioctl(dev, SPI_IOC_WR_MAX_SPEED_HZ, &i); + b = ioctl(dev, SPI_IOC_RD_MAX_SPEED_HZ, &i); + if ((a < 0) || (b < 0)) { + DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MAX SPEED\n"); + close(dev); + free(spi_device); + return LGW_SPI_ERROR; + } + + /* setting SPI to MSB first */ + i = 0; + a = ioctl(dev, SPI_IOC_WR_LSB_FIRST, &i); + b = ioctl(dev, SPI_IOC_RD_LSB_FIRST, &i); + if ((a < 0) || (b < 0)) { + DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MSB FIRST\n"); + close(dev); + free(spi_device); + return LGW_SPI_ERROR; + } + + /* setting SPI to 8 bits per word */ + i = 0; + a = ioctl(dev, SPI_IOC_WR_BITS_PER_WORD, &i); + b = ioctl(dev, SPI_IOC_RD_BITS_PER_WORD, &i); + if ((a < 0) || (b < 0)) { + DEBUG_MSG("ERROR: SPI PORT FAIL TO SET 8 BITS-PER-WORD\n"); + close(dev); + return LGW_SPI_ERROR; + } + + *spi_device = dev; + *spi_target_ptr = (void *)spi_device; + DEBUG_MSG("Note: SPI port opened and configured ok\n"); + return LGW_SPI_SUCCESS; +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* SPI release */ +int lgw_spi_close(void *spi_target) { + int spi_device; + int a; + + /* check input variables */ + CHECK_NULL(spi_target); + + /* close file & deallocate file descriptor */ + spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ + a = close(spi_device); + free(spi_target); + + /* determine return code */ + if (a < 0) { + DEBUG_MSG("ERROR: SPI PORT FAILED TO CLOSE\n"); + return LGW_SPI_ERROR; + } else { + DEBUG_MSG("Note: SPI port closed\n"); + return LGW_SPI_SUCCESS; + } +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* Simple write */ +int lgw_spi_w(void *spi_target, uint8_t address, uint8_t data) { + int spi_device; + uint8_t out_buf[2]; + struct spi_ioc_transfer k; + int a; + + /* check input variables */ + CHECK_NULL(spi_target); + if ((address & 0x80) != 0) { + DEBUG_MSG("WARNING: SPI address > 127\n"); + } + + spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ + + /* prepare frame to be sent */ + out_buf[0] = WRITE_ACCESS | (address & 0x7F); + out_buf[1] = data; + + /* I/O transaction */ + memset(&k, 0, sizeof(k)); /* clear k */ + k.tx_buf = (unsigned long) out_buf; + k.len = ARRAY_SIZE(out_buf); + k.speed_hz = SPI_SPEED; + k.cs_change = 1; + k.bits_per_word = 8; + a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); + + /* determine return code */ + if (a != 2) { + 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 */ +int lgw_spi_r(void *spi_target, uint8_t address, uint8_t *data) { + int spi_device; + uint8_t out_buf[2]; + uint8_t in_buf[ARRAY_SIZE(out_buf)]; + struct spi_ioc_transfer k; + int a; + + /* check input variables */ + CHECK_NULL(spi_target); + if ((address & 0x80) != 0) { + DEBUG_MSG("WARNING: SPI address > 127\n"); + } + CHECK_NULL(data); + + spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ + + /* prepare frame to be sent */ + out_buf[0] = READ_ACCESS | (address & 0x7F); + out_buf[1] = 0x00; + + /* I/O transaction */ + memset(&k, 0, sizeof(k)); /* clear k */ + k.tx_buf = (unsigned long) out_buf; + k.rx_buf = (unsigned long) in_buf; + k.len = ARRAY_SIZE(out_buf); + k.cs_change = 1; + a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); + + /* determine return code */ + if (a != 2) { + DEBUG_MSG("ERROR: SPI READ FAILURE\n"); + return LGW_SPI_ERROR; + } else { + DEBUG_MSG("Note: SPI read success\n"); + *data = in_buf[1]; + return LGW_SPI_SUCCESS; + } +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* Burst (multiple-byte) write */ +int lgw_spi_wb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) { + int spi_device; + uint8_t command; + struct spi_ioc_transfer k[2]; + int size_to_do, chunk_size, offset; + int byte_transfered = 0; + 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; + } + + spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ + + /* prepare command byte */ + command = WRITE_ACCESS | (address & 0x7F); + size_to_do = size; + + /* I/O transaction */ + memset(&k, 0, sizeof(k)); /* clear k */ + k[0].tx_buf = (unsigned long) &command; + k[0].len = 1; + k[0].cs_change = 0; + k[1].cs_change = 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; + k[1].tx_buf = (unsigned long)(data + offset); + k[1].len = chunk_size; + byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - 1 ); + DEBUG_PRINTF("BURST WRITE: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered); + size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ + } + + /* determine return code */ + if (byte_transfered != size) { + 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 */ +int lgw_spi_rb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) { + int spi_device; + uint8_t command; + struct spi_ioc_transfer k[2]; + int size_to_do, chunk_size, offset; + int byte_transfered = 0; + 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; + } + + spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ + + /* prepare command byte */ + command = READ_ACCESS | (address & 0x7F); + size_to_do = size; + + /* I/O transaction */ + memset(&k, 0, sizeof(k)); /* clear k */ + k[0].tx_buf = (unsigned long) &command; + k[0].len = 1; + k[0].cs_change = 0; + k[1].cs_change = 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; + k[1].rx_buf = (unsigned long)(data + offset); + k[1].len = chunk_size; + byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - 1 ); + DEBUG_PRINTF("BURST READ: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered); + size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ + } + + /* determine return code */ + if (byte_transfered != size) { + 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 ------------------------------------------------------------------ */ -- cgit v1.2.3