summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSylvain Miermont <smiermont@semtech.com>2013-08-08 15:49:31 +0200
committerSylvain Miermont <smiermont@semtech.com>2013-10-23 11:03:07 +0200
commitddac0aa483dd5f7bca31b0c042949eca370a8fdc (patch)
tree339b16655dbb9b6cca0e972454a8591256330900
parente588fccf2b13065c25c95c70be191614cd23b005 (diff)
downloadlora_gateway-ddac0aa483dd5f7bca31b0c042949eca370a8fdc.tar.gz
lora_gateway-ddac0aa483dd5f7bca31b0c042949eca370a8fdc.tar.bz2
lora_gateway-ddac0aa483dd5f7bca31b0c042949eca370a8fdc.zip
Beta 3v1.b3
- modified 'native' SPI module to align with the way resource pointers are managed in 'ftdi' variant (void pointers) - better check of channel frequency + bandwidth vs. authorized band - improved Makefile
-rw-r--r--loragw_hal/Makefile30
-rw-r--r--loragw_hal/README.txt (renamed from loragw_hal/README)4
-rw-r--r--loragw_hal/inc/loragw_hal.h3
-rw-r--r--loragw_hal/inc/loragw_spi.h24
-rw-r--r--loragw_hal/obj/.gitkeep0
-rw-r--r--loragw_hal/src/loragw_hal.c6
-rw-r--r--loragw_hal/src/loragw_reg.c51
-rw-r--r--loragw_hal/src/loragw_spi.c237
-rw-r--r--loragw_hal/test/test_loragw_spi.c34
9 files changed, 231 insertions, 158 deletions
diff --git a/loragw_hal/Makefile b/loragw_hal/Makefile
index 94d23b2..0712c25 100644
--- a/loragw_hal/Makefile
+++ b/loragw_hal/Makefile
@@ -1,35 +1,41 @@
+CC=gcc
+CFLAGS=-O2 -Iinc
+C99FLAGS=-O2 -std=c99 -Iinc
+LDFLAGS=-lrt
+
+all: test_loragw_spi test_loragw_reg test_loragw_hal
+
clean:
rm -f test_*
rm -f obj/*.o
-all: test_loragw_spi test_loragw_reg test_loragw_hal
-
test_loragw_spi: obj/test_loragw_spi.o obj/loragw_spi.o
- gcc obj/test_loragw_spi.o obj/loragw_spi.o -o test_loragw_spi
+ $(CC) obj/test_loragw_spi.o obj/loragw_spi.o -o test_loragw_spi $(LDFLAGS)
test_loragw_reg: obj/test_loragw_reg.o obj/loragw_reg.o obj/loragw_spi.o
- gcc obj/test_loragw_reg.o obj/loragw_reg.o obj/loragw_spi.o -o test_loragw_reg
+ $(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
- gcc obj/test_loragw_hal.o obj/loragw_hal.o obj/loragw_reg.o obj/loragw_spi.o obj/loragw_aux.o -lrt -o test_loragw_hal
+ $(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
- gcc -c -O2 -Iinc src/loragw_aux.c -o obj/loragw_aux.o
+ $(CC) -c $(CFLAGS) src/loragw_aux.c -o obj/loragw_aux.o
obj/loragw_spi.o: src/loragw_spi.c inc/loragw_spi.h
- gcc -c -O2 -std=c99 -Iinc src/loragw_spi.c -o obj/loragw_spi.o
+ $(CC) -c $(C99FLAGS) src/loragw_spi.c -o obj/loragw_spi.o
obj/loragw_reg.o: src/loragw_reg.c inc/loragw_reg.h inc/loragw_spi.h
- gcc -c -O2 -std=c99 -Iinc src/loragw_reg.c -o obj/loragw_reg.o
+ $(CC) -c $(C99FLAGS) src/loragw_reg.c -o obj/loragw_reg.o
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
- gcc -c -O2 -std=c99 -Iinc src/loragw_hal.c -o obj/loragw_hal.o
+ $(CC) -c $(C99FLAGS) src/loragw_hal.c -o obj/loragw_hal.o
obj/test_loragw_spi.o: test/test_loragw_spi.c inc/loragw_spi.h
- gcc -c -std=c99 -Iinc test/test_loragw_spi.c -o obj/test_loragw_spi.o
+ $(CC) -c $(C99FLAGS) -Iinc test/test_loragw_spi.c -o obj/test_loragw_spi.o
obj/test_loragw_reg.o: test/test_loragw_reg.c inc/loragw_reg.h
- gcc -c -std=c99 -Iinc test/test_loragw_reg.c -o obj/test_loragw_reg.o
+ $(CC) -c $(C99FLAGS) -Iinc test/test_loragw_reg.c -o obj/test_loragw_reg.o
obj/test_loragw_hal.o: test/test_loragw_hal.c inc/loragw_hal.h inc/loragw_aux.h
- gcc -c -std=c99 -Iinc test/test_loragw_hal.c -o obj/test_loragw_hal.o
+ $(CC) -c $(C99FLAGS) test/test_loragw_hal.c -o obj/test_loragw_hal.o
+
diff --git a/loragw_hal/README b/loragw_hal/README.txt
index 1e97a25..15034ff 100644
--- a/loragw_hal/README
+++ b/loragw_hal/README.txt
@@ -37,6 +37,7 @@ use the Lora gateway:
* lgw_stop, to stop the hardware
* lgw_receive, to fetch packets if any was received
* lgw_send, to send a single packet (non-blocking, see warning in usage section)
+* lgw_status, to check when a packet has effectively been sent
For an standard application, include only this module.
The use of this module is detailed on the usage section.
@@ -179,7 +180,8 @@ to be transmitted if the packet is triggered on a future event.
While a packet is emitted, no packet can be received (limitation intrinsic to
most radio frequency systems).
-Your application *must* take into account the time it takes to send a packet.
+Your application *must* take into account the time it takes to send a packet or
+check the status (using lgw_status) before attempting to send another packet.
Trying to send a packet while the previous packet has not finished being send
will result in the previous packet not being sent or being sent only partially
diff --git a/loragw_hal/inc/loragw_hal.h b/loragw_hal/inc/loragw_hal.h
index feecf5c..eeccaf2 100644
--- a/loragw_hal/inc/loragw_hal.h
+++ b/loragw_hal/inc/loragw_hal.h
@@ -43,7 +43,8 @@ Description:
#define LGW_PKT_FIFO_SIZE 8
#define LGW_DATABUFF_SIZE 1024
-#define LGW_RF_BANDWIDTH 800000
+#define LGW_RADIO_BW 500000 /* bandwidth of the radio */
+#define LGW_REF_BW 125000 /* typical bandwidth of data channel */
/*
SX1275 frequency setting :
diff --git a/loragw_hal/inc/loragw_spi.h b/loragw_hal/inc/loragw_spi.h
index 3ad857f..68d8bcf 100644
--- a/loragw_hal/inc/loragw_spi.h
+++ b/loragw_hal/inc/loragw_spi.h
@@ -35,57 +35,57 @@ Description:
/**
@brief Lora gateway SPI setup (configure I/O and peripherals)
-@param spi_device pointer to SPI file descriptor to be written
+@param spi_target_ptr pointer on a generic pointer to SPI target (implementation dependant)
@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
*/
-int lgw_spi_open(int *spi_device);
+int lgw_spi_open(void **spi_target_ptr);
/**
@brief Lora gateway SPI close
-@param spi_device SPI file descriptor of the port to close
+@param spi_target generic pointer to SPI target (implementation dependant)
@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
*/
-int lgw_spi_close(int spi_device);
+int lgw_spi_close(void *spi_target);
/**
@brief Lora gateway SPI single-byte write
-@param spi_device SPI file descriptor of the target port
+@param spi_target generic pointer to SPI target (implementation dependant)
@param address 7-bit register address
@param data data byte to write
@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
*/
-int lgw_spi_w(int spi_device, uint8_t address, uint8_t data);
+int lgw_spi_w(void *spi_target, uint8_t address, uint8_t data);
/**
@brief Lora gateway SPI single-byte read
-@param spi_device SPI file descriptor of the target port
+@param spi_target generic pointer to SPI target (implementation dependant)
@param address 7-bit register address
@param data data byte to write
@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
*/
-int lgw_spi_r(int spi_device, uint8_t address, uint8_t *data);
+int lgw_spi_r(void *spi_target, uint8_t address, uint8_t *data);
/**
@brief Lora gateway SPI burst (multiple-byte) write
-@param spi_device SPI file descriptor of the target port
+@param spi_target generic pointer to SPI target (implementation dependant)
@param address 7-bit register address
@param data pointer to byte array that will be sent to the Lora gateway
@param size size of the transfer, in byte(s)
@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
*/
-int lgw_spi_wb(int spi_device, uint8_t address, uint8_t *data, uint16_t size);
+int lgw_spi_wb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size);
/**
@brief Lora gateway SPI burst (multiple-byte) read
-@param spi_device SPI file descriptor of the target port
+@param spi_target generic pointer to SPI target (implementation dependant)
@param address 7-bit register address
@param data pointer to byte array that will be written from the Lora gateway
@param size size of the transfer, in byte(s)
@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
*/
-int lgw_spi_rb(int spi_device, uint8_t address, uint8_t *data, uint16_t size);
+int lgw_spi_rb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size);
#endif
diff --git a/loragw_hal/obj/.gitkeep b/loragw_hal/obj/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/loragw_hal/obj/.gitkeep
diff --git a/loragw_hal/src/loragw_hal.c b/loragw_hal/src/loragw_hal.c
index 9f9bf8a..fc9e293 100644
--- a/loragw_hal/src/loragw_hal.c
+++ b/loragw_hal/src/loragw_hal.c
@@ -440,7 +440,6 @@ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) {
}
/* check 'general' parameters */
- /* ? add checks to stay in band (ie. radio_freq+if+BW/2 < fmax) ? */
if (if_chain > LGW_IF_CHAIN_NB) {
DEBUG_PRINTF("ERROR: %d NOT A VALID IF_CHAIN NUMBER\n", if_chain);
return LGW_HAL_ERROR;
@@ -448,13 +447,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_RF_BANDWIDTH/2) {
+ if ((conf.freq_hz + LGW_REF_BW/2) > LGW_RADIO_BW/2) {
DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO HIGH\n", conf.freq_hz);
return LGW_HAL_ERROR;
- } else if (conf.freq_hz < -LGW_RF_BANDWIDTH/2) {
+ } else if ((conf.freq_hz - LGW_REF_BW/2) < -LGW_RADIO_BW/2) {
DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO LOW\n", conf.freq_hz);
return LGW_HAL_ERROR;
}
+ /* WARNING: if the channel is 250 or 500kHz wide, that check is insufficient */
/* check parameters according to the type of IF chain + modem,
fill default if necessary, and commit configuration if everything is OK */
diff --git a/loragw_hal/src/loragw_reg.c b/loragw_hal/src/loragw_reg.c
index 31da925..ab5a922 100644
--- a/loragw_hal/src/loragw_reg.c
+++ b/loragw_hal/src/loragw_reg.c
@@ -365,7 +365,7 @@ const struct lgw_reg_s loregs[LGW_TOTALREGS] = {
/* -------------------------------------------------------------------------- */
/* --- PRIVATE VARIABLES ---------------------------------------------------- */
-static int lgw_spidesc = -1; /*! file descriptor to the SPI device */
+void *lgw_spi_target = NULL; /*! generic pointer to the SPI device */
static int lgw_regpage = -1; /*! keep the value of the register page selected */
/* -------------------------------------------------------------------------- */
@@ -373,7 +373,7 @@ static int lgw_regpage = -1; /*! keep the value of the register page selected */
int page_switch(uint8_t target) {
lgw_regpage = PAGE_MASK & target;
- lgw_spi_w(lgw_spidesc, PAGE_ADDR, (uint8_t)lgw_regpage);
+ lgw_spi_w(lgw_spi_target, PAGE_ADDR, (uint8_t)lgw_regpage);
return LGW_REG_SUCCESS;
}
@@ -385,18 +385,18 @@ int lgw_connect(void) {
int spi_stat = LGW_SPI_SUCCESS;
uint8_t u = 0;
- if (lgw_spidesc >= 0) {
+ if (lgw_spi_target != NULL) {
DEBUG_MSG("WARNING: gateway was already connected\n");
- lgw_spi_close(lgw_spidesc);
+ lgw_spi_close(lgw_spi_target);
}
/* open the SPI link */
- spi_stat = lgw_spi_open(&lgw_spidesc);
+ spi_stat = lgw_spi_open(&lgw_spi_target);
if (spi_stat != LGW_SPI_SUCCESS) {
DEBUG_MSG("ERROR CONNECTING GATEWAY\n");
return LGW_REG_ERROR;
}
/* write 0 to the page/reset register */
- spi_stat = lgw_spi_w(lgw_spidesc, loregs[LGW_PAGE_REG].addr, 0);
+ spi_stat = lgw_spi_w(lgw_spi_target, loregs[LGW_PAGE_REG].addr, 0);
if (spi_stat != LGW_SPI_SUCCESS) {
DEBUG_MSG("ERROR WRITING PAGE REGISTER\n");
return LGW_REG_ERROR;
@@ -404,7 +404,7 @@ int lgw_connect(void) {
lgw_regpage = 0;
}
/* checking the version register */
- spi_stat = lgw_spi_r(lgw_spidesc, loregs[LGW_VERSION].addr, &u);
+ spi_stat = lgw_spi_r(lgw_spi_target, loregs[LGW_VERSION].addr, &u);
if (spi_stat != LGW_SPI_SUCCESS) {
DEBUG_MSG("ERROR READING VERSION REGISTER\n");
return LGW_REG_ERROR;
@@ -423,14 +423,13 @@ int lgw_connect(void) {
/* Gateway disconnect */
int lgw_disconnect(void) {
- if (lgw_spidesc >= 0) {
- lgw_spi_close(lgw_spidesc);
- lgw_spidesc = -1;
+ if (lgw_spi_target != NULL) {
+ lgw_spi_close(lgw_spi_target);
+ lgw_spi_target = NULL;
DEBUG_MSG("Note: success disconnecting the gateway\n");
return LGW_REG_SUCCESS;
} else {
DEBUG_MSG("WARNING: gateway was already disconnected\n");
- lgw_spidesc = -1;
return LGW_REG_ERROR;
}
}
@@ -441,11 +440,11 @@ int lgw_disconnect(void) {
int lgw_soft_reset(void) {
int32_t read_value;
/* check if SPI is initialised */
- if ((lgw_spidesc < 0) || (lgw_regpage < 0)) {
+ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) {
DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n");
return LGW_REG_ERROR;
}
- lgw_spi_w(lgw_spidesc, 0, 0x80); /* 1 -> SOFT_RESET bit */
+ lgw_spi_w(lgw_spi_target, 0, 0x80); /* 1 -> SOFT_RESET bit */
lgw_regpage = 0; /* reset the paging static variable */
return LGW_REG_SUCCESS;
}
@@ -462,7 +461,7 @@ int lgw_reg_check(FILE *f) {
int i;
/* check if SPI is initialised */
- if ((lgw_spidesc < 0) || (lgw_regpage < 0)) {
+ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) {
DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n");
fprintf(f, "ERROR: GATEWAY UNCONNECTED\n");
return LGW_REG_ERROR;
@@ -499,7 +498,7 @@ int lgw_reg_w(uint16_t register_id, int32_t reg_value) {
}
/* check if SPI is initialised */
- if ((lgw_spidesc < 0) || (lgw_regpage < 0)) {
+ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) {
DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n");
return LGW_REG_ERROR;
}
@@ -531,14 +530,14 @@ int lgw_reg_w(uint16_t register_id, int32_t reg_value) {
if ((r.leng == 8) && (r.offs == 0)) {
/* direct write */
- spi_stat += lgw_spi_w(lgw_spidesc, r.addr, (uint8_t)reg_value);
+ spi_stat += lgw_spi_w(lgw_spi_target, r.addr, (uint8_t)reg_value);
} else if ((r.offs + r.leng) <= 8) {
/* single-byte read-modify-write, offs:[0-7], leng:[1-7] */
- spi_stat += lgw_spi_r(lgw_spidesc, r.addr, &buf[0]);
+ spi_stat += lgw_spi_r(lgw_spi_target, r.addr, &buf[0]);
buf[1] = ((1 << r.leng) - 1) << r.offs; /* bit mask */
buf[2] = ((uint8_t)reg_value) << r.offs; /* new data offsetted */
buf[3] = (~buf[1] & buf[0]) | (buf[1] & buf[2]); /* mixing old & new data */
- spi_stat += lgw_spi_w(lgw_spidesc, r.addr, buf[3]);
+ spi_stat += lgw_spi_w(lgw_spi_target, r.addr, buf[3]);
} else if ((r.offs == 0) && (r.leng > 0) && (r.leng <= 32)) {
/* multi-byte direct write routine */
size_byte = (r.leng + 7) / 8; /* add a byte if it's not an exact multiple of 8 */
@@ -548,7 +547,7 @@ int lgw_reg_w(uint16_t register_id, int32_t reg_value) {
buf[i] = (uint8_t)(0x000000FF & reg_value);
reg_value = (reg_value >> 8);
}
- spi_stat += lgw_spi_wb(lgw_spidesc, r.addr, buf, size_byte); /* write the register in one burst */
+ spi_stat += lgw_spi_wb(lgw_spi_target, r.addr, buf, size_byte); /* write the register in one burst */
} else {
/* register spanning multiple memory bytes but with an offset */
DEBUG_MSG("ERROR: REGISTER SIZE AND OFFSET ARE NOT SUPPORTED\n");
@@ -582,7 +581,7 @@ int lgw_reg_r(uint16_t register_id, int32_t *reg_value) {
}
/* check if SPI is initialised */
- if ((lgw_spidesc < 0) || (lgw_regpage < 0)) {
+ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) {
DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n");
return LGW_REG_ERROR;
}
@@ -597,7 +596,7 @@ int lgw_reg_r(uint16_t register_id, int32_t *reg_value) {
if ((r.offs + r.leng) <= 8) {
/* read one byte, then shift and mask bits to get reg value with sign extension if needed */
- spi_stat += lgw_spi_r(lgw_spidesc, r.addr, &bufu[0]);
+ spi_stat += lgw_spi_r(lgw_spi_target, r.addr, &bufu[0]);
bufu[1] = bufu[0] << (8 - r.leng - r.offs); /* left-align the data */
if (r.sign == true) {
bufs[2] = bufs[1] >> (8 - r.leng); /* right align the data with sign extension (ARITHMETIC right shift) */
@@ -608,7 +607,7 @@ int lgw_reg_r(uint16_t register_id, int32_t *reg_value) {
}
} else if ((r.offs == 0) && (r.leng > 0) && (r.leng <= 32)) {
size_byte = (r.leng + 7) / 8; /* add a byte if it's not an exact multiple of 8 */
- spi_stat += lgw_spi_rb(lgw_spidesc, r.addr, bufu, size_byte);
+ spi_stat += lgw_spi_rb(lgw_spi_target, r.addr, bufu, size_byte);
u = 0;
for (i=(size_byte-1); i>=0; --i) {
u = (uint32_t)bufu[i] + (u << 8); /* transform a 4-byte array into a 32 bit word */
@@ -652,7 +651,7 @@ int lgw_reg_wb(uint16_t register_id, uint8_t *data, uint16_t size) {
}
/* check if SPI is initialised */
- if ((lgw_spidesc < 0) || (lgw_regpage < 0)) {
+ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) {
DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n");
return LGW_REG_ERROR;
}
@@ -672,7 +671,7 @@ int lgw_reg_wb(uint16_t register_id, uint8_t *data, uint16_t size) {
}
/* do the burst write */
- spi_stat = lgw_spi_wb(lgw_spidesc, r.addr, data, size);
+ spi_stat = lgw_spi_wb(lgw_spi_target, r.addr, data, size);
if (spi_stat != LGW_SPI_SUCCESS) {
DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST WRITE\n");
@@ -701,7 +700,7 @@ int lgw_reg_rb(uint16_t register_id, uint8_t *data, uint16_t size) {
}
/* check if SPI is initialised */
- if ((lgw_spidesc < 0) || (lgw_regpage < 0)) {
+ if ((lgw_spi_target == NULL) || (lgw_regpage < 0)) {
DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n");
return LGW_REG_ERROR;
}
@@ -715,7 +714,7 @@ int lgw_reg_rb(uint16_t register_id, uint8_t *data, uint16_t size) {
}
/* do the burst read */
- spi_stat = lgw_spi_rb(lgw_spidesc, r.addr, data, size);
+ spi_stat = lgw_spi_rb(lgw_spi_target, r.addr, data, size);
if (spi_stat != LGW_SPI_SUCCESS) {
DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST READ\n");
diff --git a/loragw_hal/src/loragw_spi.c b/loragw_hal/src/loragw_spi.c
index fa8581c..d6e3eb0 100644
--- a/loragw_hal/src/loragw_spi.c
+++ b/loragw_hal/src/loragw_spi.c
@@ -20,6 +20,7 @@ Description:
#include <stdint.h> /* C99 types */
#include <stdio.h> /* printf fprintf */
+#include <stdlib.h> /* malloc free */
#include <unistd.h> /* lseek, close */
#include <fcntl.h> /* open */
#include <string.h> /* memset */
@@ -55,70 +56,95 @@ Description:
/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
/* SPI initialization and configuration */
-int lgw_spi_open(int *spi_device) {
- int i,j,k,l;
+int lgw_spi_open(void **spi_target_ptr) {
+ int *spi_device = NULL;
+ int dev;
+ int a,b,c;
+ int i;
- CHECK_NULL(spi_device);
+ /* 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 */
- i = open(SPI_DEV_PATH, O_RDWR);
- if (i < 0) {
+ 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' */
- j = SPI_MODE_0;
- k = ioctl(i, SPI_IOC_WR_MODE, &j);
- l = ioctl(i, SPI_IOC_RD_MODE, &j);
- if ((k < 0) || (l < 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(i);
+ close(dev);
+ free(spi_device);
return LGW_SPI_ERROR;
}
/* setting SPI max clk (in Hz) */
- j = SPI_SPEED;
- k = ioctl(i, SPI_IOC_WR_MAX_SPEED_HZ, &j);
- l = ioctl(i, SPI_IOC_RD_MAX_SPEED_HZ, &j);
- if ((k < 0) || (l < 0)) {
+ 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(i);
+ close(dev);
+ free(spi_device);
return LGW_SPI_ERROR;
}
/* setting SPI to MSB first */
- j = 0;
- k = ioctl(i, SPI_IOC_WR_LSB_FIRST, &j);
- l = ioctl(i, SPI_IOC_RD_LSB_FIRST, &j);
- if ((k < 0) || (l < 0)) {
+ 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(i);
+ close(dev);
+ free(spi_device);
return LGW_SPI_ERROR;
}
/* setting SPI to 8 bits per word */
- j = 0;
- k = ioctl(i, SPI_IOC_WR_BITS_PER_WORD, &j);
- l = ioctl(i, SPI_IOC_RD_BITS_PER_WORD, &j);
- if ((k < 0) || (l < 0)) {
+ 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(i);
+ close(dev);
return LGW_SPI_ERROR;
}
- DEBUG_MSG("Note: SPI port opened and configured ok\n");
- *spi_device = i;
+
+ *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(int spi_device) {
- int i;
+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);
- i = close(spi_device);
- if (i < 0) {
+ /* determine return code */
+ if (a < 0) {
DEBUG_MSG("ERROR: SPI PORT FAILED TO CLOSE\n");
return LGW_SPI_ERROR;
} else {
@@ -130,24 +156,35 @@ int lgw_spi_close(int spi_device) {
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* Simple write */
-int lgw_spi_w(int spi_device, uint8_t address, uint8_t data) {
- uint8_t outbuf[2];
+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 i;
+ int a;
- outbuf[0] = WRITE_ACCESS | (address & 0x7F);
- outbuf[1] = data;
+ /* 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) outbuf;
- k.len = ARRAY_SIZE(outbuf);
+ 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);
- i = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
-
- if (i != 2) {
+ /* determine return code */
+ if (a != 2) {
DEBUG_MSG("ERROR: SPI WRITE FAILURE\n");
return LGW_SPI_ERROR;
} else {
@@ -159,31 +196,41 @@ int lgw_spi_w(int spi_device, uint8_t address, uint8_t data) {
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* Simple read */
-int lgw_spi_r(int spi_device, uint8_t address, uint8_t *data) {
- uint8_t outbuf[2];
- uint8_t inbuf[ARRAY_SIZE(outbuf)];
+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 i;
+ int a;
+ /* check input variables */
+ CHECK_NULL(spi_target);
+ if ((address & 0x80) != 0) {
+ DEBUG_MSG("WARNING: SPI address > 127\n");
+ }
CHECK_NULL(data);
- outbuf[0] = READ_ACCESS | (address & 0x7F);
- outbuf[1] = 0x00;
+ 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) outbuf;
- k.rx_buf = (unsigned long) inbuf;
- k.len = ARRAY_SIZE(outbuf);
+ 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);
- i = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
-
- if (i != 2) {
+ /* 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 = inbuf[1];
+ *data = in_buf[1];
return LGW_SPI_SUCCESS;
}
}
@@ -191,45 +238,48 @@ int lgw_spi_r(int spi_device, uint8_t address, uint8_t *data) {
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* Burst (multiple-byte) write */
-int lgw_spi_wb(int spi_device, uint8_t address, uint8_t *data, uint16_t size) {
+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 byte_to_trans;
- int chunk_size;
- int offset = 0;
+ 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;
}
- if (address > 0x7F) {
- DEBUG_MSG("ERROR: ADDRESS OUT OF SPI RANGE\n");
- return LGW_SPI_ERROR;
- }
- memset(&k, 0, sizeof(k)); /* clear k */
+ 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;
-
- byte_to_trans = size;
- while (byte_to_trans > 0) {
- chunk_size = (byte_to_trans < LGW_BURST_CHUNK) ? byte_to_trans : LGW_BURST_CHUNK;
+ 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", byte_to_trans, chunk_size, byte_transfered);
-
- byte_to_trans -= chunk_size;
- offset += chunk_size;
- }
+ 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;
@@ -242,45 +292,48 @@ int lgw_spi_wb(int spi_device, uint8_t address, uint8_t *data, uint16_t size) {
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* Burst (multiple-byte) read */
-int lgw_spi_rb(int spi_device, uint8_t address, uint8_t *data, uint16_t size) {
+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 byte_to_trans;
- int chunk_size;
- int offset = 0;
+ 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;
}
- if (address > 0x7F) {
- DEBUG_MSG("ERROR: ADDRESS OUT OF SPI RANGE\n");
- return LGW_SPI_ERROR;
- }
- memset(&k, 0, sizeof(k)); /* clear k */
+ 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;
-
- byte_to_trans = size;
- while (byte_to_trans > 0) {
- chunk_size = (byte_to_trans < LGW_BURST_CHUNK) ? byte_to_trans : LGW_BURST_CHUNK;
+ 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", byte_to_trans, chunk_size, byte_transfered);
-
- byte_to_trans -= chunk_size;
- offset += chunk_size;
- }
+ 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;
diff --git a/loragw_hal/test/test_loragw_spi.c b/loragw_hal/test/test_loragw_spi.c
index c5ab45b..0eae55d 100644
--- a/loragw_hal/test/test_loragw_spi.c
+++ b/loragw_hal/test/test_loragw_spi.c
@@ -29,6 +29,7 @@ Description:
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
#define BURST_TEST_SIZE 2500 /* >> LGW_BURST_CHUNK */
+#define TIMING_REPEAT 1 /* repeat transactions multiple times for timing characterisation */
/* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */
@@ -36,8 +37,8 @@ Description:
int main(int argc, char **argv)
{
int i;
- int spi_device;
- uint8_t data;
+ void *spi_target = NULL;
+ uint8_t data = 0;
uint8_t dataout[BURST_TEST_SIZE];
uint8_t datain[BURST_TEST_SIZE];
@@ -47,20 +48,31 @@ int main(int argc, char **argv)
}
printf("Beginning of test for loragw_spi.c\n");
- lgw_spi_open(&spi_device);
+ lgw_spi_open(&spi_target);
/* normal R/W test */
- lgw_spi_w(spi_device, 0xAA, 0x96);
- lgw_spi_r(spi_device, 0x55, &data);
+ for (i = 0; i < TIMING_REPEAT; ++i)
+ lgw_spi_w(spi_target, 0xAA, 0x96);
+ for (i = 0; i < TIMING_REPEAT; ++i)
+ lgw_spi_r(spi_target, 0x55, &data);
- /* burst R/W test */
- lgw_spi_wb(spi_device, 0x55, dataout, ARRAY_SIZE(dataout));
- lgw_spi_rb(spi_device, 0x55, datain, ARRAY_SIZE(datain));
+ /* burst R/W test, small bursts << LGW_BURST_CHUNK */
+ for (i = 0; i < TIMING_REPEAT; ++i)
+ lgw_spi_wb(spi_target, 0x55, dataout, 16);
+ for (i = 0; i < TIMING_REPEAT; ++i)
+ lgw_spi_rb(spi_target, 0x55, datain, 16);
- /* display results */
- printf("data received: %d\n",data);
+ /* burst R/W test, large bursts >> LGW_BURST_CHUNK */
+ for (i = 0; i < TIMING_REPEAT; ++i)
+ lgw_spi_wb(spi_target, 0x5A, dataout, ARRAY_SIZE(dataout));
+ for (i = 0; i < TIMING_REPEAT; ++i)
+ lgw_spi_rb(spi_target, 0x5A, datain, ARRAY_SIZE(datain));
- lgw_spi_close(spi_device);
+ /* last read (blocking), just to be sure no to quit before the FTDI buffer is flushed */
+ lgw_spi_r(spi_target, 0x55, &data);
+ printf("data received (simple read): %d\n",data);
+
+ lgw_spi_close(spi_target);
printf("End of test for loragw_spi.c\n");
return 0;