diff options
author | Sylvain Miermont <smiermont@semtech.com> | 2013-08-08 15:49:31 +0200 |
---|---|---|
committer | Sylvain Miermont <smiermont@semtech.com> | 2013-10-23 11:03:07 +0200 |
commit | ddac0aa483dd5f7bca31b0c042949eca370a8fdc (patch) | |
tree | 339b16655dbb9b6cca0e972454a8591256330900 | |
parent | e588fccf2b13065c25c95c70be191614cd23b005 (diff) | |
download | lora_gateway-1.b3.tar.gz lora_gateway-1.b3.tar.bz2 lora_gateway-1.b3.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/Makefile | 30 | ||||
-rw-r--r-- | loragw_hal/README.txt (renamed from loragw_hal/README) | 4 | ||||
-rw-r--r-- | loragw_hal/inc/loragw_hal.h | 3 | ||||
-rw-r--r-- | loragw_hal/inc/loragw_spi.h | 24 | ||||
-rw-r--r-- | loragw_hal/obj/.gitkeep | 0 | ||||
-rw-r--r-- | loragw_hal/src/loragw_hal.c | 6 | ||||
-rw-r--r-- | loragw_hal/src/loragw_reg.c | 51 | ||||
-rw-r--r-- | loragw_hal/src/loragw_spi.c | 237 | ||||
-rw-r--r-- | loragw_hal/test/test_loragw_spi.c | 34 |
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; |