From ddac0aa483dd5f7bca31b0c042949eca370a8fdc Mon Sep 17 00:00:00 2001 From: Sylvain Miermont Date: Thu, 8 Aug 2013 15:49:31 +0200 Subject: Beta 3 - 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 --- loragw_hal/Makefile | 30 +++-- loragw_hal/README | 195 ------------------------------- loragw_hal/README.txt | 197 +++++++++++++++++++++++++++++++ loragw_hal/inc/loragw_hal.h | 3 +- loragw_hal/inc/loragw_spi.h | 24 ++-- loragw_hal/obj/.gitkeep | 0 loragw_hal/src/loragw_hal.c | 6 +- loragw_hal/src/loragw_reg.c | 51 ++++---- loragw_hal/src/loragw_spi.c | 237 +++++++++++++++++++++++--------------- loragw_hal/test/test_loragw_spi.c | 34 ++++-- 10 files changed, 425 insertions(+), 352 deletions(-) delete mode 100644 loragw_hal/README create mode 100644 loragw_hal/README.txt create mode 100644 loragw_hal/obj/.gitkeep 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 deleted file mode 100644 index 1e97a25..0000000 --- a/loragw_hal/README +++ /dev/null @@ -1,195 +0,0 @@ -Lora Gateway HAL -================ - -1. Introduction ---------------- - -The Lora Gateway Hardware Abstraction Layer is a C library that allow you to -use a Semtech Lora gateway hardware through a reduced number of high level C -functions to configure the hardware, send and receive packets. - -The Semtech Lora gateway is a digital multi-channel multi-standard packet radio -used to send and receive packets wirelessly using Lora, FSK or GFSK -modulations. - - -2. Components of the library ----------------------------- - -The library is composed of 4 modules: - -* loragw_hal -* loragw_reg -* loragw_spi -* loragw_aux - -The library also contains 3 test program to demonstrate code use and check -functionality. - -### 2.1. loragw_hal ### - -This is the main module and contains the high level functions to configure and -use the Lora gateway: - -* lgw_rxrf_setconf, to set the configuration of the radio channels -* lgw_rxif_setconf, to set the configuration of the IF+modem channels -* lgw_start, to apply the set configuration to the hardware and start it -* 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) - -For an standard application, include only this module. -The use of this module is detailed on the usage section. - -### 2.2. loragw_reg ### - -This module is used to access to the Lora gateway registers by name instead of -by address: - -* lgw_connect, to initialise and check the connection with the hardware -* lgw_disconnect, to disconnect the hardware -* lgw_soft_reset, to reset the whole hardware by resetting the register array -* lgw_reg_check, to check all registers vs. their default value and output the -result to a file -* lgw_reg_r, read a named register -* lgw_reg_w, write a named register -* lgw_reg_rb, read a name register in burst -* lgw_reg_wb, write a named register in burst - -This module handles pagination, read-only registers protection, multi-byte -registers management, signed registers management, read-modify-write routines -for sub-byte registers and read/write burst fragmentation to respect SPI -maximum burst length constraints. - -It make the code much easier to read and to debug. -Moreover, if registers are relocated between different hardware revisions but -keep the same function, the code written using register names can be reused "as -is". - -If you need access to all the registers, include this module in your -application. - -**/!\ Warning** please be sure to have a good understanding of the Lora gateway -inner working before accessing the internal registers directly. - -### 2.3. loragw_spi ### - -This module contains the functions to access the Lora gateway register array -through the SPI interface: - -* lgw_spi_r to read one byte -* lgw_spi_w to write one byte -* lgw_spi_rb to read two bytes or more -* lgw_spi_wb to write two bytes or more - -Please *do not* include that module directly into your application. - -**/!\ Warning** Accessing the Lora gateway register array without the checks -and safety provided by the functions in loragw_reg is not recommended. - -### 2.4. loragw_aux ### - -This module contains a single host-dependant function wait_ms to pause for a -defined amount of milliseconds. - -The procedure to start and configure the Lora gateway hardware contained in the -loragw_hal module requires to wait for several milliseconds at certain steps, -typically to allow for supply voltages or clocks to stabilize after been -switched on. - -An accuracy of 1 ms or less is ideal. -If your system doesn't allow that level of accuracy, make sure that the actual -delay is *longer* that the time specified when the function is called (ie. -wait_ms(X) *MUST NOT* before X milliseconds under any circumstance). - -If the minimum delays are not guaranteed during the configuration and start -procedure, the hardware might not work at nominal performance. -Most likely, it will not work at all. - - -3. Software dependencies ------------------------- - -The library is written following ANSI C conventions but using C99 explicit -length data type for all data exchanges with hardware and for parameters. - -The loragw_aux module contains POSIX dependant functions for millisecond -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). - - -4. Hardware dependencies ------------------------- - -The loragw_reg and loragw_hal are written for a specific version on the Semtech -hardware. -The library will not work if there is a mismatch between the hardware version -and the library version. -You can use the test program test_loragw_reg to check if the hardware registers -match their software declaration. - -loragw_spi contains 4 SPI functions (read, write, burst read, burst write) that -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) -* native SPI using a microcontroller peripheral (not provided) - -You can use the test program test_loragw_spi to check with a logic analyser -that the SPI communication is working - - -5. Usage --------- - -To use the HAL in your application, you must follow some basic rules: - -* configure the radios path and IF+modem path before starting the radio -* the configuration is only transferred to hardware when you call the *start* -function -* you cannot receive packets until one (or +) radio is enabled AND one (or +) -IF+modem part is enabled AND the gateway is started -* you cannot send packets until one (or +) radio is enabled AND the gateway is -started -* you must stop the gateway before changing the configuration - -A typical application flow for using the HAL is the following: - - - -loop { - - - -} - - -To debug your application, it might help to compile the loragw_hal function -with the DEBUG flag defined. -It then send a lot of details, including detailed error messages to *stderr*. - - -**/!\ Warning** The lgw_send function is non-blocking and returns while the -Lora gateway is still sending the packet, or even before the packet has started -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. - -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 -(resulting in a CRC error in the receiver). - - -6. License ----------- - -To Be Defined. - - -*EOF* \ No newline at end of file diff --git a/loragw_hal/README.txt b/loragw_hal/README.txt new file mode 100644 index 0000000..15034ff --- /dev/null +++ b/loragw_hal/README.txt @@ -0,0 +1,197 @@ +Lora Gateway HAL +================ + +1. Introduction +--------------- + +The Lora Gateway Hardware Abstraction Layer is a C library that allow you to +use a Semtech Lora gateway hardware through a reduced number of high level C +functions to configure the hardware, send and receive packets. + +The Semtech Lora gateway is a digital multi-channel multi-standard packet radio +used to send and receive packets wirelessly using Lora, FSK or GFSK +modulations. + + +2. Components of the library +---------------------------- + +The library is composed of 4 modules: + +* loragw_hal +* loragw_reg +* loragw_spi +* loragw_aux + +The library also contains 3 test program to demonstrate code use and check +functionality. + +### 2.1. loragw_hal ### + +This is the main module and contains the high level functions to configure and +use the Lora gateway: + +* lgw_rxrf_setconf, to set the configuration of the radio channels +* lgw_rxif_setconf, to set the configuration of the IF+modem channels +* lgw_start, to apply the set configuration to the hardware and start it +* 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. + +### 2.2. loragw_reg ### + +This module is used to access to the Lora gateway registers by name instead of +by address: + +* lgw_connect, to initialise and check the connection with the hardware +* lgw_disconnect, to disconnect the hardware +* lgw_soft_reset, to reset the whole hardware by resetting the register array +* lgw_reg_check, to check all registers vs. their default value and output the +result to a file +* lgw_reg_r, read a named register +* lgw_reg_w, write a named register +* lgw_reg_rb, read a name register in burst +* lgw_reg_wb, write a named register in burst + +This module handles pagination, read-only registers protection, multi-byte +registers management, signed registers management, read-modify-write routines +for sub-byte registers and read/write burst fragmentation to respect SPI +maximum burst length constraints. + +It make the code much easier to read and to debug. +Moreover, if registers are relocated between different hardware revisions but +keep the same function, the code written using register names can be reused "as +is". + +If you need access to all the registers, include this module in your +application. + +**/!\ Warning** please be sure to have a good understanding of the Lora gateway +inner working before accessing the internal registers directly. + +### 2.3. loragw_spi ### + +This module contains the functions to access the Lora gateway register array +through the SPI interface: + +* lgw_spi_r to read one byte +* lgw_spi_w to write one byte +* lgw_spi_rb to read two bytes or more +* lgw_spi_wb to write two bytes or more + +Please *do not* include that module directly into your application. + +**/!\ Warning** Accessing the Lora gateway register array without the checks +and safety provided by the functions in loragw_reg is not recommended. + +### 2.4. loragw_aux ### + +This module contains a single host-dependant function wait_ms to pause for a +defined amount of milliseconds. + +The procedure to start and configure the Lora gateway hardware contained in the +loragw_hal module requires to wait for several milliseconds at certain steps, +typically to allow for supply voltages or clocks to stabilize after been +switched on. + +An accuracy of 1 ms or less is ideal. +If your system doesn't allow that level of accuracy, make sure that the actual +delay is *longer* that the time specified when the function is called (ie. +wait_ms(X) *MUST NOT* before X milliseconds under any circumstance). + +If the minimum delays are not guaranteed during the configuration and start +procedure, the hardware might not work at nominal performance. +Most likely, it will not work at all. + + +3. Software dependencies +------------------------ + +The library is written following ANSI C conventions but using C99 explicit +length data type for all data exchanges with hardware and for parameters. + +The loragw_aux module contains POSIX dependant functions for millisecond +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). + + +4. Hardware dependencies +------------------------ + +The loragw_reg and loragw_hal are written for a specific version on the Semtech +hardware. +The library will not work if there is a mismatch between the hardware version +and the library version. +You can use the test program test_loragw_reg to check if the hardware registers +match their software declaration. + +loragw_spi contains 4 SPI functions (read, write, burst read, burst write) that +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) +* native SPI using a microcontroller peripheral (not provided) + +You can use the test program test_loragw_spi to check with a logic analyser +that the SPI communication is working + + +5. Usage +-------- + +To use the HAL in your application, you must follow some basic rules: + +* configure the radios path and IF+modem path before starting the radio +* the configuration is only transferred to hardware when you call the *start* +function +* you cannot receive packets until one (or +) radio is enabled AND one (or +) +IF+modem part is enabled AND the gateway is started +* you cannot send packets until one (or +) radio is enabled AND the gateway is +started +* you must stop the gateway before changing the configuration + +A typical application flow for using the HAL is the following: + + + +loop { + + + +} + + +To debug your application, it might help to compile the loragw_hal function +with the DEBUG flag defined. +It then send a lot of details, including detailed error messages to *stderr*. + + +**/!\ Warning** The lgw_send function is non-blocking and returns while the +Lora gateway is still sending the packet, or even before the packet has started +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 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 +(resulting in a CRC error in the receiver). + + +6. License +---------- + +To Be Defined. + + +*EOF* \ No newline at end of file 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 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 /* C99 types */ #include /* printf fprintf */ +#include /* malloc free */ #include /* lseek, close */ #include /* open */ #include /* 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; -- cgit v1.2.3