diff options
-rw-r--r-- | loragw_hal/README | 109 | ||||
-rw-r--r-- | loragw_hal/inc/loragw_aux.h | 6 | ||||
-rw-r--r-- | loragw_hal/inc/loragw_hal.h | 205 | ||||
-rw-r--r-- | loragw_hal/inc/loragw_reg.h | 20 | ||||
-rw-r--r-- | loragw_hal/inc/loragw_spi.h | 22 | ||||
-rw-r--r-- | loragw_hal/src/agc_fw.var | 6 | ||||
-rw-r--r-- | loragw_hal/src/arb_fw.var | 6 | ||||
-rw-r--r-- | loragw_hal/src/loragw_aux.c | 44 | ||||
-rw-r--r-- | loragw_hal/src/loragw_hal.c | 1667 | ||||
-rw-r--r-- | loragw_hal/src/loragw_reg.c | 1236 | ||||
-rw-r--r-- | loragw_hal/src/loragw_spi.c | 448 | ||||
-rw-r--r-- | loragw_hal/test/test_loragw_hal.c | 397 | ||||
-rw-r--r-- | loragw_hal/test/test_loragw_reg.c | 208 | ||||
-rw-r--r-- | loragw_hal/test/test_loragw_spi.c | 66 |
14 files changed, 2247 insertions, 2193 deletions
diff --git a/loragw_hal/README b/loragw_hal/README index c8ce3d8..1e97a25 100644 --- a/loragw_hal/README +++ b/loragw_hal/README @@ -4,9 +4,13 @@ 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 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. +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 @@ -19,11 +23,13 @@ The library is composed of 4 modules: * loragw_spi * loragw_aux -The library also contains 3 test program to demonstrate code use and check functionality. - +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: +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 @@ -37,78 +43,104 @@ 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: +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_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. +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". +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. +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. +**/!\ 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: +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. +**/!\ 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. +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. +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 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. +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 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. +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). +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. +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 rewritten depending on the SPI bridge you use: +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 +You can use the test program test_loragw_spi to check with a logic analyser +that the SPI communication is working 5. Usage @@ -117,9 +149,12 @@ You can use the test program test_loragw_spi to check with a logic analyser that 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 +* 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: @@ -133,16 +168,22 @@ loop { } <stop the gateway> -To debug your application, it might help to compile the loragw_hal function with the DEBUG flag defined. +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). +**/!\ 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). +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 diff --git a/loragw_hal/inc/loragw_aux.h b/loragw_hal/inc/loragw_aux.h index a0cc7cb..09f543f 100644 --- a/loragw_hal/inc/loragw_aux.h +++ b/loragw_hal/inc/loragw_aux.h @@ -1,13 +1,13 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - Lora gateway Hardware Abstraction Layer + Lora gateway Hardware Abstraction Layer */ diff --git a/loragw_hal/inc/loragw_hal.h b/loragw_hal/inc/loragw_hal.h index 39c8ca0..1057251 100644 --- a/loragw_hal/inc/loragw_hal.h +++ b/loragw_hal/inc/loragw_hal.h @@ -1,13 +1,13 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - Lora gateway Hardware Abstraction Layer + Lora gateway Hardware Abstraction Layer */ @@ -17,24 +17,24 @@ Description: /* -------------------------------------------------------------------------- */ /* --- DEPENDANCIES --------------------------------------------------------- */ -#include <stdint.h> /* C99 types */ -#include <stdbool.h> /* bool type */ +#include <stdint.h> /* C99 types */ +#include <stdbool.h> /* bool type */ /* -------------------------------------------------------------------------- */ /* --- PUBLIC CONSTANTS ----------------------------------------------------- */ /* return status code */ -#define LGW_HAL_SUCCESS 0 -#define LGW_HAL_ERROR -1 +#define LGW_HAL_SUCCESS 0 +#define LGW_HAL_ERROR -1 /* hardware characteristics */ -#define LGW_RF_CHAIN_NB 2 /* number of RF chains */ -#define LGW_IF_CHAIN_NB 10 /* number of IF+modem RX chains */ -#define LGW_MULTI_NB 4 /* number of Lora 'multi SF' chains */ +#define LGW_RF_CHAIN_NB 2 /* number of RF chains */ +#define LGW_IF_CHAIN_NB 10 /* number of IF+modem RX chains */ +#define LGW_MULTI_NB 4 /* number of Lora 'multi SF' chains */ -#define LGW_PKT_FIFO_SIZE 8 -#define LGW_DATABUFF_SIZE 1024 -#define LGW_RF_BANDWIDTH 800000 +#define LGW_PKT_FIFO_SIZE 8 +#define LGW_DATABUFF_SIZE 1024 +#define LGW_RF_BANDWIDTH 800000 /* SX1275 frequency setting : @@ -42,79 +42,79 @@ F_register(24bit) = F_rf (Hz) / F_step(Hz) = F_rf (Hz) * 2^19 / F_xtal(Hz) = F_rf (Hz) * 256/15625 */ -#define LGW_XTAL_FREQU 32000000 -#define LGW_SW1257_DENUM 15625 /* pll settings denominator when the numerator is 2^8 */ +#define LGW_XTAL_FREQU 32000000 +#define LGW_SX1257_DENOMINATOR 15625 /* pll settings denominator when the numerator is 2^8 */ /* to use those parameters, declare a local constant, and use 'rf_chain' as index */ -#define LGW_RF_RX_LOWFREQ {863000000, 863000000} -#define LGW_RF_RX_UPFREQ {870000000, 870000000} -#define LGW_RF_TX_LOWFREQ {863000000, 863000000} -#define LGW_RF_TX_UPFREQ {870000000, 870000000} +#define LGW_RF_RX_LOWFREQ {863000000, 863000000} +#define LGW_RF_RX_UPFREQ {870000000, 870000000} +#define LGW_RF_TX_LOWFREQ {863000000, 863000000} +#define LGW_RF_TX_UPFREQ {870000000, 870000000} /* type of if_chain + modem */ -#define IF_UNDEFINED 0 -#define IF_LORA_STD 0x10 /* if + standard single-SF Lora modem */ -#define IF_LORA_MULTI 0x11 /* if + Lora receiver with multi-SF capability */ -#define IF_FSK_STD 0x20 /* if + standard FSK modem */ +#define IF_UNDEFINED 0 +#define IF_LORA_STD 0x10 /* if + standard single-SF Lora modem */ +#define IF_LORA_MULTI 0x11 /* if + Lora receiver with multi-SF capability */ +#define IF_FSK_STD 0x20 /* if + standard FSK modem */ /* configuration of available IF chains and modems on the hardware */ /* to use, declare a local constant, and use 'if_chain' as index */ #define LGW_IFMODEM_CONFIG {\ - IF_LORA_MULTI, \ - IF_LORA_MULTI, \ - IF_LORA_MULTI, \ - IF_LORA_MULTI, \ - IF_UNDEFINED, \ - IF_UNDEFINED, \ - IF_UNDEFINED, \ - IF_UNDEFINED, \ - IF_LORA_STD, \ - IF_FSK_STD } + IF_LORA_MULTI, \ + IF_LORA_MULTI, \ + IF_LORA_MULTI, \ + IF_LORA_MULTI, \ + IF_UNDEFINED, \ + IF_UNDEFINED, \ + IF_UNDEFINED, \ + IF_UNDEFINED, \ + IF_LORA_STD, \ + IF_FSK_STD } /* values available for the 'modulation' parameters */ -#define MOD_UNDEFINED 0 -#define MOD_LORA 0x10 -#define MOD_FSK 0x20 -#define MOD_GFSK 0x21 +#define MOD_UNDEFINED 0 +#define MOD_LORA 0x10 +#define MOD_FSK 0x20 +#define MOD_GFSK 0x21 /* values available for the 'bandwidth' parameters */ -#define BW_UNDEFINED 0 -#define BW_500KHZ 0x04 -#define BW_250KHZ 0x08 -#define BW_125KHZ 0x0C -// TODO: add all the supporter FSK bandwidth +#define BW_UNDEFINED 0 +#define BW_500KHZ 0x04 +#define BW_250KHZ 0x08 +#define BW_125KHZ 0x0C +// TODO: add all the supported FSK bandwidth /* values available for the 'datarate' parameters */ -#define DR_UNDEFINED 0 -#define DR_LORA_SF7 0x1002 -#define DR_LORA_SF8 0x1004 -#define DR_LORA_SF9 0x1008 -#define DR_LORA_SF10 0x1010 -#define DR_LORA_SF11 0x1020 -#define DR_LORA_SF12 0x1040 -#define DR_LORA_MULTI 0x107E -// TODO: add FSK datarates +#define DR_UNDEFINED 0 +#define DR_LORA_SF7 0x1002 +#define DR_LORA_SF8 0x1004 +#define DR_LORA_SF9 0x1008 +#define DR_LORA_SF10 0x1010 +#define DR_LORA_SF11 0x1020 +#define DR_LORA_SF12 0x1040 +#define DR_LORA_MULTI 0x107E +// TODO: add FSK data rates /* values available for the 'coderate' parameters */ -#define CR_UNDEFINED 0 -#define CR_LORA_4_5 0x11 -#define CR_LORA_4_6 0x12 -#define CR_LORA_4_7 0x13 -#define CR_LORA_4_8 0x14 +#define CR_UNDEFINED 0 +#define CR_LORA_4_5 0x11 +#define CR_LORA_4_6 0x12 +#define CR_LORA_4_7 0x13 +#define CR_LORA_4_8 0x14 /* values available for the 'status' parameter */ -#define STAT_UNDEFINED 0x00 -#define STAT_NO_CRC 0x01 -#define STAT_CRC_BAD 0x11 -#define STAT_CRC_OK 0x10 +#define STAT_UNDEFINED 0x00 +#define STAT_NO_CRC 0x01 +#define STAT_CRC_BAD 0x11 +#define STAT_CRC_OK 0x10 /* values available for the 'tx_mode' parameter */ -#define IMMEDIATE 0 -#define TIMESTAMPED 1 -#define ON_GPS 2 -//#define ON_EVENT 3 -//#define GPS_DELAYED 4 -//#define EVENT_DELAYED 5 +#define IMMEDIATE 0 +#define TIMESTAMPED 1 +#define ON_GPS 2 +//#define ON_EVENT 3 +//#define GPS_DELAYED 4 +//#define EVENT_DELAYED 5 /* -------------------------------------------------------------------------- */ /* --- PUBLIC TYPES --------------------------------------------------------- */ @@ -124,8 +124,8 @@ F_register(24bit) = F_rf (Hz) / F_step(Hz) @brief Configuration structure for a RF chain */ struct lgw_conf_rxrf_s { - bool enable; /*!> enable or disable that RF chain */ - uint32_t freq_hz; /*!> center frequency of the radio in Hz */ + bool enable; /*!> enable or disable that RF chain */ + uint32_t freq_hz; /*!> center frequency of the radio in Hz */ }; /** @@ -133,11 +133,11 @@ struct lgw_conf_rxrf_s { @brief Configuration structure for an IF chain */ struct lgw_conf_rxif_s { - bool enable; /*!> enable or disable that IF chain */ - uint8_t rf_chain; /*!> to which RF chain is that IF chain associated */ - int32_t freq_hz; /*!> center frequ of the IF chain, relative to RF chain frequency */ - uint8_t bandwidth; /*!> RX bandwidth, 0 for default */ - uint16_t datarate; /*!> RX datarate, 0 for default */ + bool enable; /*!> enable or disable that IF chain */ + uint8_t rf_chain; /*!> to which RF chain is that IF chain associated */ + int32_t freq_hz; /*!> center frequ of the IF chain, relative to RF chain frequency */ + uint8_t bandwidth; /*!> RX bandwidth, 0 for default */ + uint16_t datarate; /*!> RX datarate, 0 for default */ }; /** @@ -145,20 +145,20 @@ struct lgw_conf_rxif_s { @brief Structure containing the metadata of a packet that was received and a pointer to the payload */ struct lgw_pkt_rx_s { - uint8_t if_chain; /*!> by which IF chain was packet received */ - uint8_t status; /*!> status of the received packet */ - uint8_t modulation; /*!> modulation used by the packet */ - uint8_t bandwidth; /*!> modulation bandwidth (LORA only) */ - uint16_t datarate; /*!> RX datarate of the packet */ - uint8_t coderate; /*!> error-correcting code of the packet */ - uint32_t count_us; /*!> internal gateway counter for timestamping, 1 microsecond resolution */ - float rssi; /*!> average packet RSSI in dB */ - float snr; /*!> average packet SNR, in dB (LORA only) */ - float snr_min; /*!> minimum packet SNR, in dB (LORA only) */ - float snr_max; /*!> maximum packet SNR, in dB (LORA only) */ - uint16_t crc; /*!> CRC that was received in the payload */ - uint16_t size; /*!> payload size in bytes */ - uint8_t *payload; /*!> pointer to the payload */ + uint8_t if_chain; /*!> by which IF chain was packet received */ + uint8_t status; /*!> status of the received packet */ + uint8_t modulation; /*!> modulation used by the packet */ + uint8_t bandwidth; /*!> modulation bandwidth (Lora only) */ + uint16_t datarate; /*!> RX datarate of the packet */ + uint8_t coderate; /*!> error-correcting code of the packet */ + uint32_t count_us; /*!> internal gateway counter for timestamping, 1 microsecond resolution */ + float rssi; /*!> average packet RSSI in dB */ + float snr; /*!> average packet SNR, in dB (Lora only) */ + float snr_min; /*!> minimum packet SNR, in dB (Lora only) */ + float snr_max; /*!> maximum packet SNR, in dB (Lora only) */ + uint16_t crc; /*!> CRC that was received in the payload */ + uint16_t size; /*!> payload size in bytes */ + uint8_t *payload; /*!> pointer to the payload */ }; /** @@ -166,21 +166,22 @@ struct lgw_pkt_rx_s { @brief Structure containing the configuration of a packet to send and a pointer to the payload */ struct lgw_pkt_tx_s { - uint32_t freq_hz; /*!> center frequency of TX */ - uint8_t tx_mode; /*!> select on what event/time the TX is triggered */ - uint32_t count_us; /*!> timestamp or delay in microseconds for TX trigger */ - uint8_t rf_chain; /*!> through which RF chain will the packet be sent */ - int8_t rf_power; /*!> TX power, in dBm */ - uint8_t modulation; /*!> modulation to use for the packet */ - uint8_t bandwidth; /*!> modulation bandwidth (LORA only) */ - uint16_t f_dev; /*!> frequency deviation (FSK only) */ - uint16_t datarate; /*!> TX datarate */ - uint8_t coderate; /*!> error-correcting code of the packet */ - uint16_t preamble; /*!> set the preamble length, 0 for default */ - bool no_crc; /*!> if true, do not send a CRC in the packet */ - bool no_header; /*!> if true, enable implicit header mode */ - uint16_t size; /*!> payload size in bytes */ - uint8_t *payload; /*!> pointer to the payload */ + uint32_t freq_hz; /*!> center frequency of TX */ + uint8_t tx_mode; /*!> select on what event/time the TX is triggered */ + uint32_t count_us; /*!> timestamp or delay in microseconds for TX trigger */ + uint8_t rf_chain; /*!> through which RF chain will the packet be sent */ + int8_t rf_power; /*!> TX power, in dBm */ + uint8_t modulation; /*!> modulation to use for the packet */ + uint8_t bandwidth; /*!> modulation bandwidth (Lora only) */ + bool invert_pol; /*!> invert signal polarity, for orthogonal downlinks (Lora only) */ + uint16_t f_dev; /*!> frequency deviation (FSK only) */ + uint16_t datarate; /*!> TX datarate */ + uint8_t coderate; /*!> error-correcting code of the packet */ + uint16_t preamble; /*!> set the preamble length, 0 for default */ + bool no_crc; /*!> if true, do not send a CRC in the packet */ + bool no_header; /*!> if true, enable implicit header mode */ + uint16_t size; /*!> payload size in bytes */ + uint8_t *payload; /*!> pointer to the payload */ }; /* -------------------------------------------------------------------------- */ diff --git a/loragw_hal/inc/loragw_reg.h b/loragw_hal/inc/loragw_reg.h index e0f9390..922d3df 100644 --- a/loragw_hal/inc/loragw_reg.h +++ b/loragw_hal/inc/loragw_reg.h @@ -1,16 +1,16 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - Functions used to handle a single Lora gateway. - Registers are addressed by name. - Multi-bytes registers are handled automatically. - Read-modify-write is handled automatically. + Functions used to handle a single Lora gateway. + Registers are addressed by name. + Multi-bytes registers are handled automatically. + Read-modify-write is handled automatically. */ @@ -20,14 +20,14 @@ Description: /* -------------------------------------------------------------------------- */ /* --- DEPENDANCIES --------------------------------------------------------- */ -#include <stdint.h> /* C99 types */ -#include <stdbool.h> /* bool type */ +#include <stdint.h> /* C99 types */ +#include <stdbool.h> /* bool type */ /* -------------------------------------------------------------------------- */ /* --- PUBLIC CONSTANTS ----------------------------------------------------- */ -#define LGW_REG_SUCCESS 0 -#define LGW_REG_ERROR -1 +#define LGW_REG_SUCCESS 0 +#define LGW_REG_ERROR -1 /* auto generated register mapping for C code : 24-Jun-2013 20:29:09 diff --git a/loragw_hal/inc/loragw_spi.h b/loragw_hal/inc/loragw_spi.h index 62cdeb4..3ad857f 100644 --- a/loragw_hal/inc/loragw_spi.h +++ b/loragw_hal/inc/loragw_spi.h @@ -1,17 +1,17 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - Host specific functions to address the LoRa™ gateway registers through a - SPI interface. - Single-byte read/write and burst read/write. - Does not handle pagination. - Could be used with multiple SPI ports in parallel (explicit file descriptor) + Host specific functions to address the LoRa™ gateway registers through a + SPI interface. + Single-byte read/write and burst read/write. + Does not handle pagination. + Could be used with multiple SPI ports in parallel (explicit file descriptor) */ @@ -21,14 +21,14 @@ Description: /* -------------------------------------------------------------------------- */ /* --- DEPENDANCIES --------------------------------------------------------- */ -#include <stdint.h> /* C99 types*/ +#include <stdint.h> /* C99 types*/ /* -------------------------------------------------------------------------- */ /* --- PUBLIC CONSTANTS ----------------------------------------------------- */ -#define LGW_SPI_SUCCESS 0 -#define LGW_SPI_ERROR -1 -#define LGW_BURST_CHUNK 1024 +#define LGW_SPI_SUCCESS 0 +#define LGW_SPI_ERROR -1 +#define LGW_BURST_CHUNK 1024 /* -------------------------------------------------------------------------- */ /* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */ diff --git a/loragw_hal/src/agc_fw.var b/loragw_hal/src/agc_fw.var index 350e56d..a0dde65 100644 --- a/loragw_hal/src/agc_fw.var +++ b/loragw_hal/src/agc_fw.var @@ -1,13 +1,13 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - AGC firmware + AGC firmware */ static uint8_t agc_firmware[MCU_AGC_FW_BYTE] = { diff --git a/loragw_hal/src/arb_fw.var b/loragw_hal/src/arb_fw.var index 2e41dcc..2cb66f5 100644 --- a/loragw_hal/src/arb_fw.var +++ b/loragw_hal/src/arb_fw.var @@ -1,13 +1,13 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - Arbiter firmware + Arbiter firmware */ static uint8_t arb_firmware[MCU_ARB_FW_BYTE] = { diff --git a/loragw_hal/src/loragw_aux.c b/loragw_hal/src/loragw_aux.c index 52df612..9adafe3 100644 --- a/loragw_hal/src/loragw_aux.c +++ b/loragw_hal/src/loragw_aux.c @@ -1,31 +1,31 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - Lora gateway auxiliary functions + Lora gateway auxiliary functions */ /* -------------------------------------------------------------------------- */ /* --- DEPENDANCIES --------------------------------------------------------- */ -#include <stdio.h> /* printf fprintf */ -#include <time.h> /* clock_nanosleep */ +#include <stdio.h> /* printf fprintf */ +#include <time.h> /* clock_nanosleep */ /* -------------------------------------------------------------------------- */ /* --- PRIVATE MACROS ------------------------------------------------------- */ #ifdef DEBUG - #define DEBUG_MSG(str) fprintf(stderr, str) - #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) + #define DEBUG_MSG(str) fprintf(stderr, str) + #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) #else - #define DEBUG_MSG(str) - #define DEBUG_PRINTF(fmt, args...) + #define DEBUG_MSG(str) + #define DEBUG_PRINTF(fmt, args...) #endif /* -------------------------------------------------------------------------- */ @@ -33,19 +33,19 @@ Description: /* This implementation is POSIX-pecific and require a fix to be compatible with C99 */ void wait_ms(unsigned long a) { - struct timespec dly; - struct timespec rem; - - dly.tv_sec = a / 1000; - dly.tv_nsec = ((long)a % 1000) * 1000000; - - DEBUG_PRINTF("NOTE dly: %ld sec %ld ns\n", dly.tv_sec, dly.tv_nsec); - - if((dly.tv_sec > 0) || ((dly.tv_sec == 0) && (dly.tv_nsec > 100000))) { - clock_nanosleep(CLOCK_MONOTONIC, 0, &dly, &rem); - DEBUG_PRINTF("NOTE remain: %ld sec %ld ns\n", rem.tv_sec, rem.tv_nsec); - } - return; + struct timespec dly; + struct timespec rem; + + dly.tv_sec = a / 1000; + dly.tv_nsec = ((long)a % 1000) * 1000000; + + DEBUG_PRINTF("NOTE dly: %ld sec %ld ns\n", dly.tv_sec, dly.tv_nsec); + + if((dly.tv_sec > 0) || ((dly.tv_sec == 0) && (dly.tv_nsec > 100000))) { + clock_nanosleep(CLOCK_MONOTONIC, 0, &dly, &rem); + DEBUG_PRINTF("NOTE remain: %ld sec %ld ns\n", rem.tv_sec, rem.tv_nsec); + } + return; } /* --- EOF ------------------------------------------------------------------ */ diff --git a/loragw_hal/src/loragw_hal.c b/loragw_hal/src/loragw_hal.c index bdf563c..d597f5d 100644 --- a/loragw_hal/src/loragw_hal.c +++ b/loragw_hal/src/loragw_hal.c @@ -1,24 +1,25 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - Lora gateway Hardware Abstraction Layer + Lora gateway Hardware Abstraction Layer */ /* -------------------------------------------------------------------------- */ /* --- DEPENDANCIES --------------------------------------------------------- */ -#include <stdint.h> /* C99 types */ -#include <stdlib.h> /* malloc & free */ -#include <stdbool.h> /* bool type */ -#include <stdio.h> /* printf fprintf */ -#include <math.h> /* NaN */ +#include <stdint.h> /* C99 types */ +#include <stdlib.h> /* malloc & free */ +#include <stdbool.h> /* bool type */ +#include <stdio.h> /* printf fprintf */ +#include <math.h> /* NaN */ +#include <string.h> /* memcpy */ #include "loragw_reg.h" #include "loragw_hal.h" @@ -29,15 +30,15 @@ Description: #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #ifdef DEBUG - #define DEBUG_MSG(str) fprintf(stderr, str) - #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) - #define DEBUG_ARRAY(a,b,c) for(a=0;a<b;++a) fprintf(stderr,"%x.",c[a]);fprintf(stderr,"end\n") - #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_HAL_ERROR;} + #define DEBUG_MSG(str) fprintf(stderr, str) + #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) + #define DEBUG_ARRAY(a,b,c) for(a=0;a<b;++a) fprintf(stderr,"%x.",c[a]);fprintf(stderr,"end\n") + #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_HAL_ERROR;} #else - #define DEBUG_MSG(str) - #define DEBUG_PRINTF(fmt, args...) - #define DEBUG_ARRAY(a,b,c) - #define CHECK_NULL(a) if(a==NULL){return LGW_HAL_ERROR;} + #define DEBUG_MSG(str) + #define DEBUG_PRINTF(fmt, args...) + #define DEBUG_ARRAY(a,b,c) + #define CHECK_NULL(a) if(a==NULL){return LGW_HAL_ERROR;} #endif #define IF_HZ_TO_REG(f) (f << 5)/15625 @@ -45,8 +46,8 @@ Description: /* -------------------------------------------------------------------------- */ /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ -#define MCU_ARB 0 -#define MCU_AGC 1 +#define MCU_ARB 0 +#define MCU_AGC 1 const uint8_t ifmod_config[LGW_IF_CHAIN_NB] = LGW_IFMODEM_CONFIG; /* define hardware capability */ @@ -55,29 +56,30 @@ const uint32_t rf_rx_upfreq[LGW_RF_CHAIN_NB] = LGW_RF_RX_UPFREQ; const uint32_t rf_tx_lowfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_LOWFREQ; const uint32_t rf_tx_upfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_UPFREQ; -#define MCU_ARB_FW_BYTE 2048 /* size of the firmware IN BYTES (= twice the number of 14b words) */ -#define MCU_AGC_FW_BYTE 8192 /* size of the firmware IN BYTES (= twice the number of 14b words) */ +#define MCU_ARB_FW_BYTE 2048 /* size of the firmware IN BYTES (= twice the number of 14b words) */ +#define MCU_AGC_FW_BYTE 8192 /* size of the firmware IN BYTES (= twice the number of 14b words) */ -#define SX1257_CLK_OUT 1 -#define SX1257_TX_DAC_CLK_SEL 1 /* 0:int, 1:ext */ -#define SX1257_TX_DAC_GAIN 2 /* 3:0, 2:-3, 1:-6, 0:-9 dBFS (default 2) */ -#define SX1257_TX_MIX_GAIN 14 /* -38 + 2*TxMixGain dB (default 14) */ -#define SX1257_TX_PLL_BW 3 /* 0:75, 1:150, 2:225, 3:300 kHz (default 3) */ -#define SX1257_TX_ANA_BW 0 /* 17.5 / 2*(41-TxAnaBw) MHz (default 0) */ -#define SX1257_TX_DAC_BW 7 /* 24 + 8*TxDacBw Nb FIR taps (default 2) */ -#define SX1257_RX_LNA_GAIN 1 /* 1 to 6, 1 highest gain */ -#define SX1257_RX_BB_GAIN 12 /* 0 to 15 , 15 highest gain */ -#define SX1257_RX_ADC_BW 7 /* 0 to 7, 2:100<BW<200, 5:200<BW<400,7:400<BW (kHz) */ -#define SX1257_RX_ADC_TRIM 7 /* 0 to 7, 6 for 32MHz ref, 5 for 36MHz ref */ -#define SX1257_RXBB_BW 2 +#define SX1257_CLK_OUT 1 +#define SX1257_TX_DAC_CLK_SEL 1 /* 0:int, 1:ext */ +#define SX1257_TX_DAC_GAIN 2 /* 3:0, 2:-3, 1:-6, 0:-9 dBFS (default 2) */ +#define SX1257_TX_MIX_GAIN 14 /* -38 + 2*TxMixGain dB (default 14) */ +#define SX1257_TX_PLL_BW 3 /* 0:75, 1:150, 2:225, 3:300 kHz (default 3) */ +#define SX1257_TX_ANA_BW 0 /* 17.5 / 2*(41-TxAnaBw) MHz (default 0) */ +#define SX1257_TX_DAC_BW 7 /* 24 + 8*TxDacBw Nb FIR taps (default 2) */ +#define SX1257_RX_LNA_GAIN 1 /* 1 to 6, 1 highest gain */ +#define SX1257_RX_BB_GAIN 12 /* 0 to 15 , 15 highest gain */ +#define SX1257_RX_ADC_BW 7 /* 0 to 7, 2:100<BW<200, 5:200<BW<400,7:400<BW (kHz) */ +#define SX1257_RX_ADC_TRIM 7 /* 0 to 7, 6 for 32MHz ref, 5 for 36MHz ref */ +#define SX1257_RXBB_BW 2 -#define RSSI_OFFSET_LORA_MULTI -100.0 // TODO -#define RSSI_OFFSET_LORA_STD -100.0 // TODO +#define RSSI_OFFSET_LORA_MULTI -100.0 // TODO: need to find proper value with calibration +#define RSSI_OFFSET_LORA_STD -100.0 // TODO: need to find proper value with calibration -#define TX_METADATA_NB 16 -#define RX_METADATA_NB 16 +#define TX_METADATA_NB 16 +#define RX_METADATA_NB 16 -#define MIN_LORA_PREAMBLE 4 +#define MIN_LORA_PREAMBLE 4 +#define PLL_LOCK_MAX_ATTEMPTS 6 /* -------------------------------------------------------------------------- */ /* --- PRIVATE VARIABLES ---------------------------------------------------- */ @@ -120,7 +122,7 @@ void sx125x_write(uint8_t rf_chain, uint8_t addr, uint8_t data); uint8_t sx125x_read(uint8_t rf_chain, uint8_t addr); -void setup_sx1257(uint8_t rf_chain, uint32_t freq_hz); +int setup_sx1257(uint8_t rf_chain, uint32_t freq_hz); void lgw_constant_adjust(void); @@ -129,846 +131,855 @@ void lgw_constant_adjust(void); /* size is the firmware size in bytes (not 14b words) */ int load_firmware(uint8_t target, uint8_t *firmware, uint16_t size) { - int i; - int32_t read_value; - int reg_rst; - int reg_sel; - - /* check parameters */ - CHECK_NULL(firmware); - if (target == MCU_ARB) { - if (size != MCU_ARB_FW_BYTE) { - DEBUG_MSG("ERROR: NOT A VALID SIZE FOR MCU ARG FIRMWARE\n"); - return -1; - } - reg_rst = LGW_MCU_RST_0; - reg_sel = LGW_MCU_SELECT_MUX_0; - }else if (target == MCU_AGC) { - if (size != MCU_AGC_FW_BYTE) { - DEBUG_MSG("ERROR: NOT A VALID SIZE FOR MCU AGC FIRMWARE\n"); - return -1; - } - reg_rst = LGW_MCU_RST_1; - reg_sel = LGW_MCU_SELECT_MUX_1; - } else { - DEBUG_MSG("ERROR: NOT A VALID TARGET FOR LOADING FIRMWARE\n"); - return -1; - } - - /* reset the targeted MCU */ - lgw_reg_w(reg_rst, 1); - - /* set mux to access MCU program RAM and set address to 0 */ - lgw_reg_w(reg_sel, 0); - lgw_reg_w(LGW_MCU_PROM_ADDR, 0); - - /* write the program in one burst */ - lgw_reg_wb(LGW_MCU_PROM_DATA, firmware, size); - - /* give back control of the MCU program ram to the MCU */ - lgw_reg_w(reg_sel, 1); - - return 0; + int32_t read_value; + int reg_rst; + int reg_sel; + + /* check parameters */ + CHECK_NULL(firmware); + if (target == MCU_ARB) { + if (size != MCU_ARB_FW_BYTE) { + DEBUG_MSG("ERROR: NOT A VALID SIZE FOR MCU ARG FIRMWARE\n"); + return -1; + } + reg_rst = LGW_MCU_RST_0; + reg_sel = LGW_MCU_SELECT_MUX_0; + }else if (target == MCU_AGC) { + if (size != MCU_AGC_FW_BYTE) { + DEBUG_MSG("ERROR: NOT A VALID SIZE FOR MCU AGC FIRMWARE\n"); + return -1; + } + reg_rst = LGW_MCU_RST_1; + reg_sel = LGW_MCU_SELECT_MUX_1; + } else { + DEBUG_MSG("ERROR: NOT A VALID TARGET FOR LOADING FIRMWARE\n"); + return -1; + } + + /* reset the targeted MCU */ + lgw_reg_w(reg_rst, 1); + + /* set mux to access MCU program RAM and set address to 0 */ + lgw_reg_w(reg_sel, 0); + lgw_reg_w(LGW_MCU_PROM_ADDR, 0); + + /* write the program in one burst */ + lgw_reg_wb(LGW_MCU_PROM_DATA, firmware, size); + + /* give back control of the MCU program ram to the MCU */ + lgw_reg_w(reg_sel, 1); + + return 0; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void sx125x_write(uint8_t channel, uint8_t addr, uint8_t data) { - int reg_add, reg_dat, reg_cs; - - /* checking input parameters */ - if (channel >= LGW_RF_CHAIN_NB) { - DEBUG_MSG("ERROR: INVALID RF_CHAIN\n"); - return; - } - if (addr >= 0x7F) { - DEBUG_MSG("ERROR: ADDRESS OUT OF RANGE\n"); - return; - } - - /* selecting the target radio */ - switch (channel) { - case 0: - reg_add = LGW_SPI_RADIO_A__ADDR; - reg_dat = LGW_SPI_RADIO_A__DATA; - reg_cs = LGW_SPI_RADIO_A__CS; - break; - - case 1: - reg_add = LGW_SPI_RADIO_B__ADDR; - reg_dat = LGW_SPI_RADIO_B__DATA; - reg_cs = LGW_SPI_RADIO_B__CS; - break; - - default: - DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", channel); - return; - } - - /* SPI master data write procedure */ - lgw_reg_w(reg_add, 0x80 | addr); /* MSB at 1 for write operation */ - lgw_reg_w(reg_dat, data); - lgw_reg_w(reg_cs, 1); - lgw_reg_w(reg_cs, 0); - - return; + int reg_add, reg_dat, reg_cs; + + /* checking input parameters */ + if (channel >= LGW_RF_CHAIN_NB) { + DEBUG_MSG("ERROR: INVALID RF_CHAIN\n"); + return; + } + if (addr >= 0x7F) { + DEBUG_MSG("ERROR: ADDRESS OUT OF RANGE\n"); + return; + } + + /* selecting the target radio */ + switch (channel) { + case 0: + reg_add = LGW_SPI_RADIO_A__ADDR; + reg_dat = LGW_SPI_RADIO_A__DATA; + reg_cs = LGW_SPI_RADIO_A__CS; + break; + + case 1: + reg_add = LGW_SPI_RADIO_B__ADDR; + reg_dat = LGW_SPI_RADIO_B__DATA; + reg_cs = LGW_SPI_RADIO_B__CS; + break; + + default: + DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", channel); + return; + } + + /* SPI master data write procedure */ + lgw_reg_w(reg_cs, 0); + lgw_reg_w(reg_add, 0x80 | addr); /* MSB at 1 for write operation */ + lgw_reg_w(reg_dat, data); + lgw_reg_w(reg_cs, 1); + lgw_reg_w(reg_cs, 0); + + return; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ uint8_t sx125x_read(uint8_t channel, uint8_t addr) { - int reg_add, reg_dat, reg_cs, reg_rb; - int32_t read_value; - - /* checking input parameters */ - if (channel >= LGW_RF_CHAIN_NB) { - DEBUG_MSG("ERROR: INVALID RF_CHAIN\n"); - return 0; - } - if (addr >= 0x7F) { - DEBUG_MSG("ERROR: ADDRESS OUT OF RANGE\n"); - return 0; - } - - /* selecting the target radio */ - switch (channel) { - case 0: - reg_add = LGW_SPI_RADIO_A__ADDR; - reg_dat = LGW_SPI_RADIO_A__DATA; - reg_cs = LGW_SPI_RADIO_A__CS; - reg_rb = LGW_SPI_RADIO_A__DATA_READBACK; - break; - - case 1: - reg_add = LGW_SPI_RADIO_B__ADDR; - reg_dat = LGW_SPI_RADIO_B__DATA; - reg_cs = LGW_SPI_RADIO_B__CS; - reg_rb = LGW_SPI_RADIO_B__DATA_READBACK; - break; - - default: - DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", channel); - return 0; - } - - /* SPI master data read procedure */ - lgw_reg_w(reg_add, addr); /* MSB at 0 for read operation */ - lgw_reg_w(reg_dat, 0); - lgw_reg_w(reg_cs, 1); - lgw_reg_w(reg_cs, 0); - lgw_reg_r(reg_rb, &read_value); - - return (uint8_t)read_value; + int reg_add, reg_dat, reg_cs, reg_rb; + int32_t read_value; + + /* checking input parameters */ + if (channel >= LGW_RF_CHAIN_NB) { + DEBUG_MSG("ERROR: INVALID RF_CHAIN\n"); + return 0; + } + if (addr >= 0x7F) { + DEBUG_MSG("ERROR: ADDRESS OUT OF RANGE\n"); + return 0; + } + + /* selecting the target radio */ + switch (channel) { + case 0: + reg_add = LGW_SPI_RADIO_A__ADDR; + reg_dat = LGW_SPI_RADIO_A__DATA; + reg_cs = LGW_SPI_RADIO_A__CS; + reg_rb = LGW_SPI_RADIO_A__DATA_READBACK; + break; + + case 1: + reg_add = LGW_SPI_RADIO_B__ADDR; + reg_dat = LGW_SPI_RADIO_B__DATA; + reg_cs = LGW_SPI_RADIO_B__CS; + reg_rb = LGW_SPI_RADIO_B__DATA_READBACK; + break; + + default: + DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", channel); + return 0; + } + + /* SPI master data read procedure */ + lgw_reg_w(reg_cs, 0); + lgw_reg_w(reg_add, addr); /* MSB at 0 for read operation */ + lgw_reg_w(reg_dat, 0); + lgw_reg_w(reg_cs, 1); + lgw_reg_w(reg_cs, 0); + lgw_reg_r(reg_rb, &read_value); + + return (uint8_t)read_value; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -void setup_sx1257(uint8_t rf_chain, uint32_t freq_hz) { - uint32_t part_int; - uint32_t part_frac; - int i = 0; - - if (rf_chain >= LGW_RF_CHAIN_NB) { - DEBUG_MSG("ERROR: INVALID RF_CHAIN\n"); - return; - } - - /* misc */ - sx125x_write(rf_chain, 0x10, SX1257_TX_DAC_CLK_SEL + SX1257_CLK_OUT*2); - - /* Tx gain and trim */ - sx125x_write(rf_chain, 0x08, SX1257_TX_MIX_GAIN + SX1257_TX_DAC_GAIN*16); - sx125x_write(rf_chain, 0x0A, SX1257_TX_ANA_BW + SX1257_TX_PLL_BW*32); - sx125x_write(rf_chain, 0x0B, SX1257_TX_DAC_BW); - - /* Rx gain and trim */ - sx125x_write(rf_chain, 0x0C, 0 + SX1257_RX_BB_GAIN*2 + SX1257_RX_LNA_GAIN*32); - sx125x_write(rf_chain, 0x0D, SX1257_RXBB_BW + SX1257_RX_ADC_TRIM*4 + SX1257_RX_ADC_BW*32); - - /* set RX PLL frequency */ - part_int = freq_hz / LGW_SW1257_DENUM; /* integer part, gives the MSB and the middle byte */ - part_frac = ((freq_hz % LGW_SW1257_DENUM) << 8) / LGW_SW1257_DENUM; /* fractional part, gives LSB */ - sx125x_write(rf_chain, 0x01,0xFF & (part_int >> 8)); /* Most Significant Byte */ - sx125x_write(rf_chain, 0x02,0xFF & part_int); /* middle byte */ - sx125x_write(rf_chain, 0x03,0xFF & part_frac); /* Least Significant Byte */ - - /* start and PLL lock */ - do { - sx125x_write(rf_chain, 0x00, 1); /* enable Xtal oscillator */ - sx125x_write(rf_chain, 0x00, 3); /* Enable RX (PLL+FE) */ - ++i; - DEBUG_PRINTF("Note: SX1257 #%d PLL start (attempt %d)\n", rf_chain, i); - wait_ms(1); - } while(sx125x_read(rf_chain, 0x11) & 0x02 == 0); - - return; +int setup_sx1257(uint8_t rf_chain, uint32_t freq_hz) { + uint32_t part_int; + uint32_t part_frac; + int i = 0; + + if (rf_chain >= LGW_RF_CHAIN_NB) { + DEBUG_MSG("ERROR: INVALID RF_CHAIN\n"); + return -1; + } + + /* misc */ + sx125x_write(rf_chain, 0x10, SX1257_TX_DAC_CLK_SEL + SX1257_CLK_OUT*2); + + /* Tx gain and trim */ + sx125x_write(rf_chain, 0x08, SX1257_TX_MIX_GAIN + SX1257_TX_DAC_GAIN*16); + sx125x_write(rf_chain, 0x0A, SX1257_TX_ANA_BW + SX1257_TX_PLL_BW*32); + sx125x_write(rf_chain, 0x0B, SX1257_TX_DAC_BW); + + /* Rx gain and trim */ + sx125x_write(rf_chain, 0x0C, 0 + SX1257_RX_BB_GAIN*2 + SX1257_RX_LNA_GAIN*32); + sx125x_write(rf_chain, 0x0D, SX1257_RXBB_BW + SX1257_RX_ADC_TRIM*4 + SX1257_RX_ADC_BW*32); + + /* set RX PLL frequency */ + part_int = freq_hz / LGW_SX1257_DENOMINATOR; /* integer part, gives the MSB and the middle byte */ + part_frac = ((freq_hz % LGW_SX1257_DENOMINATOR) << 8) / LGW_SX1257_DENOMINATOR; /* fractional part, gives LSB */ + sx125x_write(rf_chain, 0x01,0xFF & (part_int >> 8)); /* Most Significant Byte */ + sx125x_write(rf_chain, 0x02,0xFF & part_int); /* middle byte */ + sx125x_write(rf_chain, 0x03,0xFF & part_frac); /* Least Significant Byte */ + + /* start and PLL lock */ + do { + if (i >= PLL_LOCK_MAX_ATTEMPTS) { + DEBUG_MSG("ERROR: FAIL TO LOCK PLL\n"); + return -1; + } + sx125x_write(rf_chain, 0x00, 1); /* enable Xtal oscillator */ + sx125x_write(rf_chain, 0x00, 3); /* Enable RX (PLL+FE) */ + ++i; + DEBUG_PRINTF("Note: SX1257 #%d PLL start (attempt %d)\n", rf_chain, i); + wait_ms(1); + } while(sx125x_read(rf_chain, 0x11) & 0x02 == 0); + + return 0; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void lgw_constant_adjust(void) { - - /* I/Q path setup */ - // lgw_reg_w(LGW_RX_INVERT_IQ,0); /* default 0 */ - // lgw_reg_w(LGW_MODEM_INVERT_IQ,1); /* default 1 */ - // lgw_reg_w(LGW_CHIRP_INVERT_RX,1); /* default 1 */ - // lgw_reg_w(LGW_RX_EDGE_SELECT,0); /* default 0 */ - // lgw_reg_w(LGW_MBWSSF_MODEM_INVERT_IQ,0); /* default 0 */ - lgw_reg_w(LGW_DC_NOTCH_EN,1); /* default 0 */ - // lgw_reg_w(LGW_RSSI_BB_FILTER_ALPHA,7); /* default 7 */ - lgw_reg_w(LGW_RSSI_DEC_FILTER_ALPHA,7); /* default 5 */ - lgw_reg_w(LGW_RSSI_CHANN_FILTER_ALPHA,7); /* default 8 */ - // lgw_reg_w(LGW_RSSI_BB_DEFAULT_VALUE,32); /* default 32 */ - lgw_reg_w(LGW_RSSI_CHANN_DEFAULT_VALUE,90); /* default 100 */ - lgw_reg_w(LGW_RSSI_DEC_DEFAULT_VALUE,90); /* default 100 */ - - /* Correlator setup */ - // lgw_reg_w(LGW_CORR_DETECT_EN,126); /* default 126 */ - // lgw_reg_w(LGW_CORR_NUM_SAME_PEAK,4); /* default 4 */ - // lgw_reg_w(LGW_CORR_MAC_GAIN,5); /* default 5 */ - // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF6,0); /* default 0 */ - // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF7,1); /* default 1 */ - // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF8,1); /* default 1 */ - // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF9,1); /* default 1 */ - // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF10,1); /* default 1 */ - // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF11,1); /* default 1 */ - // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF12,1); /* default 1 */ - // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF6,4); /* default 4 */ - // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF7,4); /* default 4 */ - // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF8,4); /* default 4 */ - // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF9,4); /* default 4 */ - // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF10,4); /* default 4 */ - // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF11,4); /* default 4 */ - // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF12,4); /* default 4 */ - - /* Lora 'multi' modems setup */ - lgw_reg_w(LGW_PREAMBLE_SYMB1_NB,4); /* default 10 */ - // lgw_reg_w(LGW_FREQ_TO_TIME_DRIFT,9); /* default 9 */ - // lgw_reg_w(LGW_FREQ_TO_TIME_INVERT,29); /* default 29 */ - // lgw_reg_w(LGW_FRAME_SYNCH_GAIN,1); /* default 1 */ - // lgw_reg_w(LGW_SYNCH_DETECT_TH,1); /* default 1 */ - // lgw_reg_w(LGW_ZERO_PAD,0); /* default 0 */ - lgw_reg_w(LGW_SNR_AVG_CST,3); /* default 2 */ - // lgw_reg_w(LGW_PPM_OFFSET,0); /* default 0 */ - // lgw_reg_w(LGW_FRAME_SYNCH_PEAK1_POS,1); /* default 1 */ - // lgw_reg_w(LGW_FRAME_SYNCH_PEAK2_POS,2); /* default 2 */ - // lgw_reg_w(LGW_PREAMBLE_FINE_TIMING_GAIN,1); /* default 1 */ - // lgw_reg_w(LGW_ONLY_CRC_EN,1); /* default 1 */ - // lgw_reg_w(LGW_PAYLOAD_FINE_TIMING_GAIN,2); /* default 2 */ - // lgw_reg_w(LGW_TRACKING_INTEGRAL,0); /* default 0 */ - // lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_RDX8,0); /* default 0 */ - // lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_RDX4,0); /* default 0 */ - // lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4,4092); /* default 4092 */ - // lgw_reg_w(LGW_MAX_PAYLOAD_LEN,255); /* default 255 */ - - /* MBWSSF Modem */ - // lgw_reg_w(LGW_MBWSSF_MODEM_ENABLE,1); /* default 0 */ - // lgw_reg_w(LGW_MBWSSF_PREAMBLE_SYMB1_NB,10); /* default 10 */ - // lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_DRIFT,36); /* default 36 */ - // lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_INVERT,29); /* default 29 */ - // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_GAIN,1); /* default 1 */ - // lgw_reg_w(LGW_MBWSSF_SYNCH_DETECT_TH,1); /* default 1 */ - // lgw_reg_w(LGW_MBWSSF_ZERO_PAD,0); /* default 0 */ - // lgw_reg_w(LGW_MBWSSF_PPM_OFFSET,0); /* default 0 */ - // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK1_POS,1); /* default 1 */ - // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS,2); /* default 2 */ - // lgw_reg_w(LGW_MBWSSF_ONLY_CRC_EN,1); /* default 1 */ - // lgw_reg_w(LGW_MBWSSF_PAYLOAD_FINE_TIMING_GAIN,2); /* default 2 */ - // lgw_reg_w(LGW_MBWSSF_PREAMBLE_FINE_TIMING_GAIN,1); /* default 1 */ - // lgw_reg_w(LGW_MBWSSF_TRACKING_INTEGRAL,0); /* default 0 */ - // lgw_reg_w(LGW_MBWSSF_AGC_FREEZE_ON_DETECT,1); /* default 1 */ - - /* TX */ - // lgw_reg_w(LGW_TX_MODE,0); /* default 0 */ - lgw_reg_w(LGW_TX_START_DELAY,5000); /* default 0 */ - - return; + + /* I/Q path setup */ + // lgw_reg_w(LGW_RX_INVERT_IQ,0); /* default 0 */ + // lgw_reg_w(LGW_MODEM_INVERT_IQ,1); /* default 1 */ + // lgw_reg_w(LGW_CHIRP_INVERT_RX,1); /* default 1 */ + // lgw_reg_w(LGW_RX_EDGE_SELECT,0); /* default 0 */ + // lgw_reg_w(LGW_MBWSSF_MODEM_INVERT_IQ,0); /* default 0 */ + lgw_reg_w(LGW_DC_NOTCH_EN,1); /* default 0 */ + // lgw_reg_w(LGW_RSSI_BB_FILTER_ALPHA,7); /* default 7 */ + lgw_reg_w(LGW_RSSI_DEC_FILTER_ALPHA,7); /* default 5 */ + lgw_reg_w(LGW_RSSI_CHANN_FILTER_ALPHA,7); /* default 8 */ + // lgw_reg_w(LGW_RSSI_BB_DEFAULT_VALUE,32); /* default 32 */ + lgw_reg_w(LGW_RSSI_CHANN_DEFAULT_VALUE,90); /* default 100 */ + lgw_reg_w(LGW_RSSI_DEC_DEFAULT_VALUE,90); /* default 100 */ + + /* Correlator setup */ + // lgw_reg_w(LGW_CORR_DETECT_EN,126); /* default 126 */ + // lgw_reg_w(LGW_CORR_NUM_SAME_PEAK,4); /* default 4 */ + // lgw_reg_w(LGW_CORR_MAC_GAIN,5); /* default 5 */ + // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF6,0); /* default 0 */ + // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF7,1); /* default 1 */ + // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF8,1); /* default 1 */ + // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF9,1); /* default 1 */ + // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF10,1); /* default 1 */ + // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF11,1); /* default 1 */ + // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF12,1); /* default 1 */ + // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF6,4); /* default 4 */ + // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF7,4); /* default 4 */ + // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF8,4); /* default 4 */ + // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF9,4); /* default 4 */ + // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF10,4); /* default 4 */ + // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF11,4); /* default 4 */ + // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF12,4); /* default 4 */ + + /* Lora 'multi' modems setup */ + lgw_reg_w(LGW_PREAMBLE_SYMB1_NB,4); /* default 10 */ + // lgw_reg_w(LGW_FREQ_TO_TIME_DRIFT,9); /* default 9 */ + // lgw_reg_w(LGW_FREQ_TO_TIME_INVERT,29); /* default 29 */ + // lgw_reg_w(LGW_FRAME_SYNCH_GAIN,1); /* default 1 */ + // lgw_reg_w(LGW_SYNCH_DETECT_TH,1); /* default 1 */ + // lgw_reg_w(LGW_ZERO_PAD,0); /* default 0 */ + lgw_reg_w(LGW_SNR_AVG_CST,3); /* default 2 */ + // lgw_reg_w(LGW_PPM_OFFSET,0); /* default 0 */ + // lgw_reg_w(LGW_FRAME_SYNCH_PEAK1_POS,1); /* default 1 */ + // lgw_reg_w(LGW_FRAME_SYNCH_PEAK2_POS,2); /* default 2 */ + // lgw_reg_w(LGW_PREAMBLE_FINE_TIMING_GAIN,1); /* default 1 */ + // lgw_reg_w(LGW_ONLY_CRC_EN,1); /* default 1 */ + // lgw_reg_w(LGW_PAYLOAD_FINE_TIMING_GAIN,2); /* default 2 */ + // lgw_reg_w(LGW_TRACKING_INTEGRAL,0); /* default 0 */ + // lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_RDX8,0); /* default 0 */ + // lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_RDX4,0); /* default 0 */ + // lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4,4092); /* default 4092 */ + // lgw_reg_w(LGW_MAX_PAYLOAD_LEN,255); /* default 255 */ + + /* MBWSSF Modem */ + // lgw_reg_w(LGW_MBWSSF_MODEM_ENABLE,1); /* default 0 */ + // lgw_reg_w(LGW_MBWSSF_PREAMBLE_SYMB1_NB,10); /* default 10 */ + // lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_DRIFT,36); /* default 36 */ + // lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_INVERT,29); /* default 29 */ + // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_GAIN,1); /* default 1 */ + // lgw_reg_w(LGW_MBWSSF_SYNCH_DETECT_TH,1); /* default 1 */ + // lgw_reg_w(LGW_MBWSSF_ZERO_PAD,0); /* default 0 */ + // lgw_reg_w(LGW_MBWSSF_PPM_OFFSET,0); /* default 0 */ + // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK1_POS,1); /* default 1 */ + // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS,2); /* default 2 */ + // lgw_reg_w(LGW_MBWSSF_ONLY_CRC_EN,1); /* default 1 */ + // lgw_reg_w(LGW_MBWSSF_PAYLOAD_FINE_TIMING_GAIN,2); /* default 2 */ + // lgw_reg_w(LGW_MBWSSF_PREAMBLE_FINE_TIMING_GAIN,1); /* default 1 */ + // lgw_reg_w(LGW_MBWSSF_TRACKING_INTEGRAL,0); /* default 0 */ + // lgw_reg_w(LGW_MBWSSF_AGC_FREEZE_ON_DETECT,1); /* default 1 */ + + /* TX */ + // lgw_reg_w(LGW_TX_MODE,0); /* default 0 */ + lgw_reg_w(LGW_TX_START_DELAY,5000); /* default 0 */ + lgw_reg_w(LGW_TX_SWAP_IQ,1); /* "normal" polarity; default 0 */ + + return; } /* -------------------------------------------------------------------------- */ /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ int lgw_rxrf_setconf(uint8_t rf_chain, struct lgw_conf_rxrf_s conf) { - - /* check if the gateway is running */ - if (lgw_is_started == true) { - DEBUG_MSG("ERROR: GATEWAY IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n"); - return LGW_HAL_ERROR; - } - - /* check input parameters */ - if (rf_chain > LGW_RF_CHAIN_NB) { - DEBUG_MSG("ERROR: NOT A VALID RF_CHAIN NUMBER\n"); - return LGW_HAL_ERROR; - } - if (conf.freq_hz > rf_rx_upfreq[rf_chain]) { - DEBUG_MSG("ERROR: FREQUENCY TOO HIGH FOR THAT RF_CHAIN\n"); - return LGW_HAL_ERROR; - } else if (conf.freq_hz < rf_rx_lowfreq[rf_chain]) { - DEBUG_MSG("ERROR: FREQUENCY TOO LOW FOR THAT RF_CHAIN\n"); - return LGW_HAL_ERROR; - } - - /* set internal config according to parameters */ - rf_enable[rf_chain] = conf.enable; - rf_rx_freq[rf_chain] = conf.freq_hz; - - return LGW_HAL_SUCCESS; + + /* check if the gateway is running */ + if (lgw_is_started == true) { + DEBUG_MSG("ERROR: GATEWAY IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n"); + return LGW_HAL_ERROR; + } + + /* check input parameters */ + if (rf_chain > LGW_RF_CHAIN_NB) { + DEBUG_MSG("ERROR: NOT A VALID RF_CHAIN NUMBER\n"); + return LGW_HAL_ERROR; + } + if (conf.freq_hz > rf_rx_upfreq[rf_chain]) { + DEBUG_MSG("ERROR: FREQUENCY TOO HIGH FOR THAT RF_CHAIN\n"); + return LGW_HAL_ERROR; + } else if (conf.freq_hz < rf_rx_lowfreq[rf_chain]) { + DEBUG_MSG("ERROR: FREQUENCY TOO LOW FOR THAT RF_CHAIN\n"); + return LGW_HAL_ERROR; + } + + /* set internal config according to parameters */ + rf_enable[rf_chain] = conf.enable; + rf_rx_freq[rf_chain] = conf.freq_hz; + + return LGW_HAL_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) { - int i, j; /* tmp variables, to shorten long 'if' lines */ - - /* check if the gateway is running */ - if (lgw_is_started == true) { - DEBUG_MSG("ERROR: GATEWAY IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n"); - return LGW_HAL_ERROR; - } - - /* if chain is disabled, don't care about most parameters */ - if (conf.enable == false) { - if_enable[if_chain] = false; - if_freq[if_chain] = 0; - DEBUG_PRINTF("Note: if_chain %d disabled\n", if_chain); - return LGW_HAL_SUCCESS; - } - - /* 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; - } - 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) { - 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) { - DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO LOW\n", conf.freq_hz); - return LGW_HAL_ERROR; - } - - /* check parameters according to the type of IF chain + modem, - fill default if necessary, and commit configuration if everything is OK */ - switch (ifmod_config[if_chain]) { - case IF_LORA_STD: - if (conf.rf_chain != 0) { - DEBUG_MSG("ERROR: LORA_STD IF CHAIN CAN ONLY BE ASSOCIATED TO RF_CHAIN 0\n"); - return LGW_HAL_ERROR; - } - /* fill default parameters if needed */ - i = (conf.bandwidth == 0) ? BW_250KHZ : conf.bandwidth; - j = (conf.datarate == 0) ? DR_LORA_SF9 : conf.datarate; - /* check BW & DR */ - if ((i != BW_125KHZ) && (i != BW_250KHZ) && (i != BW_500KHZ)) { - DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA_STD IF CHAIN\n"); - return LGW_HAL_ERROR; - } - if ((j!=DR_LORA_SF7)&&(j!=DR_LORA_SF8)&&(j!=DR_LORA_SF9)&&(j!=DR_LORA_SF10)&&(j!=DR_LORA_SF11)&&(j!=DR_LORA_SF12)) { - DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY LORA_STD IF CHAIN\n"); - return LGW_HAL_ERROR; - } - /* set internal configuration */ - if_enable[if_chain] = conf.enable; - if_freq[if_chain] = conf.freq_hz; - lora_rx_bw = i; - lora_rx_sf = j; - DEBUG_PRINTF("Note: Lora 'std' if_chain %d configured; en:%d freq:%d bw:%d dr:%d\n", if_chain, if_enable[if_chain], if_freq[if_chain], lora_rx_bw, lora_rx_sf); - break; - - case IF_LORA_MULTI: - if (conf.rf_chain >= LGW_RF_CHAIN_NB) { - DEBUG_MSG("ERROR: INVALID RF_CHAIN TO ASSOCIATE WITH A LORA_STD IF CHAIN\n"); - return LGW_HAL_ERROR; - } - /* fill default parameters if needed */ - i = (conf.bandwidth == 0) ? BW_125KHZ : conf.bandwidth; - j = (conf.datarate == 0) ? DR_LORA_MULTI : conf.datarate; - /* check BW & DR */ - if (i != BW_125KHZ) { - DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA_MULTI IF CHAIN\n"); - return LGW_HAL_ERROR; - } - if ((j & DR_LORA_MULTI) == 0) { /* supports any combination of SF between 7 and 12 */ - DEBUG_MSG("ERROR: DATARATE(S) NOT SUPPORTED BY LORA_MULTI IF CHAIN\n"); - return LGW_HAL_ERROR; - } - /* set internal configuration */ - if_enable[if_chain] = conf.enable; - switch (conf.rf_chain) { - case 0: if_rf_switch &= ~((uint8_t)1 << if_chain); break; /* force a 0 at the if_chain-th position */ - case 1: if_rf_switch |= ((uint8_t)1 << if_chain); break; /* force a 1 at the if_chain-th position */ - default: DEBUG_MSG("ERROR: IMPROPRER IF_CHAIN/RF_CHAIN ASSOCIATION\n"); - } - if_freq[if_chain] = conf.freq_hz; - lora_multi_sfmask[if_chain] = (uint8_t)j; - DEBUG_PRINTF("Note: Lora 'multi' if_chain %d configured; en:%d freq:%d SF_mask:0x%02x\n", if_chain, if_enable[if_chain], if_freq[if_chain], lora_multi_sfmask[if_chain]); - DEBUG_PRINTF("Note: rf/if switch state 0x%02x\n", if_rf_switch); - break; - - // case IF_FSK_STD: - // TODO - - default: - DEBUG_PRINTF("ERROR: IF CHAIN %d TYPE NOT SUPPORTED\n", if_chain); - return LGW_HAL_ERROR; - } - - return LGW_HAL_SUCCESS; + int i, j; /* tmp variables, to shorten long 'if' lines */ + + /* check if the gateway is running */ + if (lgw_is_started == true) { + DEBUG_MSG("ERROR: GATEWAY IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n"); + return LGW_HAL_ERROR; + } + + /* if chain is disabled, don't care about most parameters */ + if (conf.enable == false) { + if_enable[if_chain] = false; + if_freq[if_chain] = 0; + DEBUG_PRINTF("Note: if_chain %d disabled\n", if_chain); + return LGW_HAL_SUCCESS; + } + + /* 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; + } + 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) { + 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) { + DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO LOW\n", conf.freq_hz); + return LGW_HAL_ERROR; + } + + /* check parameters according to the type of IF chain + modem, + fill default if necessary, and commit configuration if everything is OK */ + switch (ifmod_config[if_chain]) { + case IF_LORA_STD: + if (conf.rf_chain != 0) { + DEBUG_MSG("ERROR: LORA_STD IF CHAIN CAN ONLY BE ASSOCIATED TO RF_CHAIN 0\n"); + return LGW_HAL_ERROR; + } + /* fill default parameters if needed */ + i = (conf.bandwidth == 0) ? BW_250KHZ : conf.bandwidth; + j = (conf.datarate == 0) ? DR_LORA_SF9 : conf.datarate; + /* check BW & DR */ + if ((i != BW_125KHZ) && (i != BW_250KHZ) && (i != BW_500KHZ)) { + DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA_STD IF CHAIN\n"); + return LGW_HAL_ERROR; + } + if ((j!=DR_LORA_SF7)&&(j!=DR_LORA_SF8)&&(j!=DR_LORA_SF9)&&(j!=DR_LORA_SF10)&&(j!=DR_LORA_SF11)&&(j!=DR_LORA_SF12)) { + DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY LORA_STD IF CHAIN\n"); + return LGW_HAL_ERROR; + } + /* set internal configuration */ + if_enable[if_chain] = conf.enable; + if_freq[if_chain] = conf.freq_hz; + lora_rx_bw = i; + lora_rx_sf = j; + DEBUG_PRINTF("Note: Lora 'std' if_chain %d configured; en:%d freq:%d bw:%d dr:%d\n", if_chain, if_enable[if_chain], if_freq[if_chain], lora_rx_bw, lora_rx_sf); + break; + + case IF_LORA_MULTI: + if (conf.rf_chain >= LGW_RF_CHAIN_NB) { + DEBUG_MSG("ERROR: INVALID RF_CHAIN TO ASSOCIATE WITH A LORA_STD IF CHAIN\n"); + return LGW_HAL_ERROR; + } + /* fill default parameters if needed */ + i = (conf.bandwidth == 0) ? BW_125KHZ : conf.bandwidth; + j = (conf.datarate == 0) ? DR_LORA_MULTI : conf.datarate; + /* check BW & DR */ + if (i != BW_125KHZ) { + DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA_MULTI IF CHAIN\n"); + return LGW_HAL_ERROR; + } + if ((j & ~DR_LORA_MULTI) != 0) { /* ones outside of DR_LORA_MULTI bitmask -> not a combination of Lora datarates */ + DEBUG_MSG("ERROR: DATARATE(S) NOT SUPPORTED BY LORA_MULTI IF CHAIN\n"); + return LGW_HAL_ERROR; + } + /* set internal configuration */ + if_enable[if_chain] = conf.enable; + switch (conf.rf_chain) { + case 0: if_rf_switch &= ~((uint8_t)1 << if_chain); break; /* force a 0 at the if_chain-th position */ + case 1: if_rf_switch |= ((uint8_t)1 << if_chain); break; /* force a 1 at the if_chain-th position */ + default: DEBUG_MSG("ERROR: IMPROPRER IF_CHAIN/RF_CHAIN ASSOCIATION\n"); + } + if_freq[if_chain] = conf.freq_hz; + lora_multi_sfmask[if_chain] = (uint8_t)j; + DEBUG_PRINTF("Note: Lora 'multi' if_chain %d configured; en:%d freq:%d SF_mask:0x%02x\n", if_chain, if_enable[if_chain], if_freq[if_chain], lora_multi_sfmask[if_chain]); + DEBUG_PRINTF("Note: rf/if switch state 0x%02x\n", if_rf_switch); + break; + + // case IF_FSK_STD: + // TODO: fill the correct metadata for a FSK packet to be sent + + default: + DEBUG_PRINTF("ERROR: IF CHAIN %d TYPE NOT SUPPORTED\n", if_chain); + return LGW_HAL_ERROR; + } + + return LGW_HAL_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_start(void) { - int reg_stat; - int32_t read_value; - int i, j; - - if (lgw_is_started == true) { - DEBUG_MSG("Note: Lora Gateway already started, restarting it now\n"); - } - - reg_stat = lgw_connect(); - if (reg_stat == LGW_REG_ERROR) { - DEBUG_MSG("ERROR: FAIL TO CONNECT BOARD\n"); - return LGW_HAL_ERROR; - } - - /* reset the registers (also shuts the radios down) */ - lgw_soft_reset(); - - /* Ungate clock (gated by default), needed for SPI master to SX1257 */ - lgw_reg_w(LGW_CLK32M_EN, 1); - lgw_reg_w(LGW_CLKHS_EN, 1); - - /* switch on and reset the radios (also starts the 32 MHz XTAL) */ - lgw_reg_w(LGW_RADIO_A_EN,1); /* radio A *must* be started to get 32 MHz clk */ - lgw_reg_w(LGW_RADIO_B_EN,1); /* radio B *must* be started because ?????? */ - wait_ms(500); - lgw_reg_w(LGW_RADIO_RST,1); - wait_ms(5); - lgw_reg_w(LGW_RADIO_RST,0); - - /* setup the radios */ - if (rf_enable[0] == 1) { - setup_sx1257(0, rf_rx_freq[0]); - } - if (rf_enable[1] == 1) { - setup_sx1257(1, rf_rx_freq[1]); - } - - /* gives the AGC MCU control over radio, RF front-end and filter gain */ - lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL,0); - lgw_reg_w(LGW_FORCE_HOST_FE_CTRL,0); - lgw_reg_w(LGW_FORCE_DEC_FILTER_GAIN,0); - - // /* TODO load the calibration firmware and wait for calibration to end */ - // load_firmware(MCU_AGC, cal_firmware, ARRAY_SIZE(cal_firmware)); - // lgw_reg_w(LGW_MCU_RST, 0); /* start the AGC MCU */ - // lgw_reg_w(LGW_FORCE_HOST_REG_CTRL,0); /* let the AGC MCU control the registers */ - // do { - // lgw_reg_r(LGW_VERSION, &read_value); - // } while (read_value == 0); - // lgw_reg_w(LGW_MCU_RST, 3); /* reset all MCU */ - - /* in the absence of calibration firmware, do a "manual" calibration */ - lgw_reg_w(LGW_TX_OFFSET_I,10); - lgw_reg_w(LGW_TX_OFFSET_Q,5); - lgw_reg_w(LGW_IQ_MISMATCH_A_AMP_COEFF,63); - lgw_reg_w(LGW_IQ_MISMATCH_A_PHI_COEFF,9); - lgw_reg_w(LGW_IQ_MISMATCH_B_AMP_COEFF,0); - lgw_reg_w(LGW_IQ_MISMATCH_B_PHI_COEFF,0); - - /* load adjusted parameters */ - lgw_constant_adjust(); - // lgw_reg_w(LGW_PPM_OFFSET,0); /* default 0 */ - - /* configure Lora 'multi' (aka. Lora 'sensor' channels */ - lgw_reg_w(LGW_RADIO_SELECT, if_rf_switch); /* IF mapping to radio A/B (per bit, 0=A, 1=B) */ - - lgw_reg_w(LGW_IF_FREQ_0, IF_HZ_TO_REG(if_freq[0])); /* default -384 */ - lgw_reg_w(LGW_IF_FREQ_1, IF_HZ_TO_REG(if_freq[1])); /* default -128 */ - lgw_reg_w(LGW_IF_FREQ_2, IF_HZ_TO_REG(if_freq[2])); /* default 128 */ - lgw_reg_w(LGW_IF_FREQ_3, IF_HZ_TO_REG(if_freq[3])); /* default 384 */ - - lgw_reg_w(LGW_CORR0_DETECT_EN, (if_enable[0] == true) ? lora_multi_sfmask[0] : 0); /* default 0 */ - lgw_reg_w(LGW_CORR1_DETECT_EN, (if_enable[1] == true) ? lora_multi_sfmask[1] : 0); /* default 0 */ - lgw_reg_w(LGW_CORR2_DETECT_EN, (if_enable[2] == true) ? lora_multi_sfmask[2] : 0); /* default 0 */ - lgw_reg_w(LGW_CORR3_DETECT_EN, (if_enable[3] == true) ? lora_multi_sfmask[3] : 0); /* default 0 */ - - lgw_reg_w(LGW_PPM_OFFSET, 0x00); /* if the threshold is 16ms, use 0x60 to enable ppm_offset for SF12 and SF11 */ - - lgw_reg_w(LGW_CONCENTRATOR_MODEM_ENABLE,1); /* default 0 */ - - /* configure Lora 'stand-alone' modem */ - lgw_reg_w(LGW_IF_FREQ_8, IF_HZ_TO_REG(if_freq[8])); /* MBWSSF modem (default 0) */ - if (if_enable[8] == true) { - switch(lora_rx_bw) { - case BW_125KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW,0); break; - case BW_250KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW,1); break; - case BW_500KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW,2); break; - default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", lora_rx_bw); - } - switch(lora_rx_sf) { - case DR_LORA_SF7: lgw_reg_w(LGW_MBWSSF_RATE_SF,7); break; - case DR_LORA_SF8: lgw_reg_w(LGW_MBWSSF_RATE_SF,8); break; - case DR_LORA_SF9: lgw_reg_w(LGW_MBWSSF_RATE_SF,9); break; - case DR_LORA_SF10: lgw_reg_w(LGW_MBWSSF_RATE_SF,10); break; - case DR_LORA_SF11: lgw_reg_w(LGW_MBWSSF_RATE_SF,11); break; - case DR_LORA_SF12: lgw_reg_w(LGW_MBWSSF_RATE_SF,12); break; - default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", lora_rx_sf); - } - lgw_reg_w(LGW_MBWSSF_PPM_OFFSET,0); /* default 0 */ - lgw_reg_w(LGW_MBWSSF_MODEM_ENABLE, 1); /* default 0 */ - } else { - lgw_reg_w(LGW_MBWSSF_MODEM_ENABLE, 0); - } - - /* configure FSK modem */ - //lgw_reg_w(LGW_IF_FREQ_9, IF_HZ_TO_REG(if_freq[9])); /* FSK modem (default 0) */ - - /* Load firmware */ - load_firmware(MCU_ARB, arb_firmware, MCU_ARB_FW_BYTE); - load_firmware(MCU_AGC, agc_firmware, MCU_AGC_FW_BYTE); - - /* Get MCUs out of reset */ - lgw_reg_w(LGW_MCU_RST_0, 0); - lgw_reg_w(LGW_MCU_RST_1, 0); - - /* Show that nanoC is configured (LED 602 green, blue at reset)*/ - lgw_reg_w(LGW_LED_REG, 5); - - lgw_is_started = true; - return LGW_HAL_SUCCESS; + int reg_stat; + int32_t read_value; + int i, j; + + if (lgw_is_started == true) { + DEBUG_MSG("Note: Lora Gateway already started, restarting it now\n"); + } + + reg_stat = lgw_connect(); + if (reg_stat == LGW_REG_ERROR) { + DEBUG_MSG("ERROR: FAIL TO CONNECT BOARD\n"); + return LGW_HAL_ERROR; + } + + /* reset the registers (also shuts the radios down) */ + lgw_soft_reset(); + + /* Ungate clock (gated by default), needed for SPI master to SX1257 */ + lgw_reg_w(LGW_CLK32M_EN, 1); + lgw_reg_w(LGW_CLKHS_EN, 1); + + /* switch on and reset the radios (also starts the 32 MHz XTAL) */ + lgw_reg_w(LGW_RADIO_A_EN,1); /* radio A *must* be started to get 32 MHz clk */ + lgw_reg_w(LGW_RADIO_B_EN,1); /* radio B *must* be started because they share the same XTAL I/O is clamped to ground when off */ + wait_ms(500); + lgw_reg_w(LGW_RADIO_RST,1); + wait_ms(5); + lgw_reg_w(LGW_RADIO_RST,0); + + /* setup the radios */ + if (rf_enable[0] == 1) { + setup_sx1257(0, rf_rx_freq[0]); + } + if (rf_enable[1] == 1) { + setup_sx1257(1, rf_rx_freq[1]); + } + + /* gives the AGC MCU control over radio, RF front-end and filter gain */ + lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL,0); + lgw_reg_w(LGW_FORCE_HOST_FE_CTRL,0); + lgw_reg_w(LGW_FORCE_DEC_FILTER_GAIN,0); + + // /* TODO load the calibration firmware and wait for calibration to end */ + // load_firmware(MCU_AGC, cal_firmware, ARRAY_SIZE(cal_firmware)); + // lgw_reg_w(LGW_MCU_RST, 0); /* start the AGC MCU */ + // lgw_reg_w(LGW_FORCE_HOST_REG_CTRL,0); /* let the AGC MCU control the registers */ + // do { + // lgw_reg_r(LGW_VERSION, &read_value); + // } while (read_value == 0); + // lgw_reg_w(LGW_MCU_RST, 3); /* reset all MCU */ + + /* in the absence of calibration firmware, do a "manual" calibration */ + lgw_reg_w(LGW_TX_OFFSET_I,10); + lgw_reg_w(LGW_TX_OFFSET_Q,5); + lgw_reg_w(LGW_IQ_MISMATCH_A_AMP_COEFF,63); + lgw_reg_w(LGW_IQ_MISMATCH_A_PHI_COEFF,9); + lgw_reg_w(LGW_IQ_MISMATCH_B_AMP_COEFF,0); + lgw_reg_w(LGW_IQ_MISMATCH_B_PHI_COEFF,0); + + /* load adjusted parameters */ + lgw_constant_adjust(); + // lgw_reg_w(LGW_PPM_OFFSET,0); /* default 0 */ + + /* configure Lora 'multi' (aka. Lora 'sensor' channels */ + lgw_reg_w(LGW_RADIO_SELECT, if_rf_switch); /* IF mapping to radio A/B (per bit, 0=A, 1=B) */ + + lgw_reg_w(LGW_IF_FREQ_0, IF_HZ_TO_REG(if_freq[0])); /* default -384 */ + lgw_reg_w(LGW_IF_FREQ_1, IF_HZ_TO_REG(if_freq[1])); /* default -128 */ + lgw_reg_w(LGW_IF_FREQ_2, IF_HZ_TO_REG(if_freq[2])); /* default 128 */ + lgw_reg_w(LGW_IF_FREQ_3, IF_HZ_TO_REG(if_freq[3])); /* default 384 */ + + lgw_reg_w(LGW_CORR0_DETECT_EN, (if_enable[0] == true) ? lora_multi_sfmask[0] : 0); /* default 0 */ + lgw_reg_w(LGW_CORR1_DETECT_EN, (if_enable[1] == true) ? lora_multi_sfmask[1] : 0); /* default 0 */ + lgw_reg_w(LGW_CORR2_DETECT_EN, (if_enable[2] == true) ? lora_multi_sfmask[2] : 0); /* default 0 */ + lgw_reg_w(LGW_CORR3_DETECT_EN, (if_enable[3] == true) ? lora_multi_sfmask[3] : 0); /* default 0 */ + + lgw_reg_w(LGW_PPM_OFFSET, 0x00); /* if the threshold is 16ms, use 0x60 to enable ppm_offset for SF12 and SF11 */ + + lgw_reg_w(LGW_CONCENTRATOR_MODEM_ENABLE,1); /* default 0 */ + + /* configure Lora 'stand-alone' modem */ + lgw_reg_w(LGW_IF_FREQ_8, IF_HZ_TO_REG(if_freq[8])); /* MBWSSF modem (default 0) */ + if (if_enable[8] == true) { + switch(lora_rx_bw) { + case BW_125KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW,0); break; + case BW_250KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW,1); break; + case BW_500KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW,2); break; + default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", lora_rx_bw); return LGW_HAL_ERROR; + } + switch(lora_rx_sf) { + case DR_LORA_SF7: lgw_reg_w(LGW_MBWSSF_RATE_SF,7); break; + case DR_LORA_SF8: lgw_reg_w(LGW_MBWSSF_RATE_SF,8); break; + case DR_LORA_SF9: lgw_reg_w(LGW_MBWSSF_RATE_SF,9); break; + case DR_LORA_SF10: lgw_reg_w(LGW_MBWSSF_RATE_SF,10); break; + case DR_LORA_SF11: lgw_reg_w(LGW_MBWSSF_RATE_SF,11); break; + case DR_LORA_SF12: lgw_reg_w(LGW_MBWSSF_RATE_SF,12); break; + default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", lora_rx_sf); return LGW_HAL_ERROR; + } + lgw_reg_w(LGW_MBWSSF_PPM_OFFSET,0); /* default 0 */ + lgw_reg_w(LGW_MBWSSF_MODEM_ENABLE, 1); /* default 0 */ + } else { + lgw_reg_w(LGW_MBWSSF_MODEM_ENABLE, 0); + } + + /* configure FSK modem */ + //lgw_reg_w(LGW_IF_FREQ_9, IF_HZ_TO_REG(if_freq[9])); /* FSK modem (default 0) */ + + /* Load firmware */ + load_firmware(MCU_ARB, arb_firmware, MCU_ARB_FW_BYTE); + load_firmware(MCU_AGC, agc_firmware, MCU_AGC_FW_BYTE); + + /* Get MCUs out of reset */ + lgw_reg_w(LGW_MCU_RST_0, 0); + lgw_reg_w(LGW_MCU_RST_1, 0); + + /* Show that nanoC is configured (LED 602 green, blue at reset)*/ + lgw_reg_w(LGW_LED_REG, 5); + + lgw_is_started = true; + return LGW_HAL_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_stop(void) { - lgw_soft_reset(); - lgw_disconnect(); - - lgw_is_started = false; - return LGW_HAL_SUCCESS; + lgw_soft_reset(); + lgw_disconnect(); + + lgw_is_started = false; + return LGW_HAL_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) { - int nb_pkt_fetch; /* loop variable and return value */ - struct lgw_pkt_rx_s *p; /* pointer to the current structure in the struct array */ - uint8_t buff[255+RX_METADATA_NB]; /* buffer to store the result of SPI read bursts */ - uint16_t data_addr; /* address read from the FIFO and programmed before the data buffer read operation */ - int s; /* size of the payload, uses to address metadata */ - int ifmod; /* type of if_chain/modem a packet was received by */ - int stat_fifo; /* the packet status as indicated in the FIFO */ - int j; - - /* check if the gateway is running */ - if (lgw_is_started == false) { - DEBUG_MSG("ERROR: GATEWAY IS NOT RUNNING, START IT BEFORE RECEIVING\n"); - return LGW_HAL_ERROR; - } - - /* check input variables */ - if (max_pkt <= 0) { - DEBUG_PRINTF("ERROR: %d = INVALID MAX NUMBER OF PACKETS TO FETCH\n", max_pkt); - return LGW_HAL_ERROR; - } - CHECK_NULL(pkt_data); - - /* iterate max_pkt times at most */ - for (nb_pkt_fetch = 0; nb_pkt_fetch < max_pkt; ++nb_pkt_fetch) { - - /* point to the proper struct in the struct array */ - p = &pkt_data[nb_pkt_fetch]; - - /* fetch all the RX FIFO data */ - lgw_reg_rb(LGW_RX_PACKET_DATA_FIFO_NUM_STORED, buff, 5); - - /* how many packets are in the RX buffer ? Break if zero */ - if (buff[0] == 0) { - DEBUG_MSG("Note: RX packet buffer empty, receive function returning nothing\n"); - break; /* no more packets to fetch, exit out of FOR loop */ - } - - DEBUG_PRINTF("FIFO content: %x %x %x %x %x\n",buff[0],buff[1],buff[2],buff[3],buff[4]); - - p->size = buff[4]; - s = p->size; - stat_fifo = buff[3]; /* will be used later, need to save it before overwriting buff */ - - /* STILL required */ - data_addr = (uint16_t)buff[1] + ((uint16_t)buff[2] << 8); - lgw_reg_w(LGW_RX_DATA_BUF_ADDR, data_addr); - - /* dynamically allocate memory to store payload */ - p->payload = (uint8_t *)malloc(s); - if (p->payload == NULL) { - /* not enough memory to allocate for payload, abort with error */ - DEBUG_MSG("ERROR: IMPOSSIBLE TO ALLOCATE MEMORY TO FETCH PAYLOAD\n"); - return LGW_HAL_ERROR; - } - - /* get payload + metadata */ - lgw_reg_rb(LGW_RX_DATA_BUF_DATA, buff, s+RX_METADATA_NB); - - /* copy payload */ - for (j = 0; j < s; ++j) { - p->payload[j] = buff[j]; - } - - /* process metadata */ - p->if_chain = buff[s+0]; - ifmod = ifmod_config[p->if_chain]; - DEBUG_PRINTF("[%d %d]\n", p->if_chain, ifmod); - - if ((ifmod == IF_LORA_MULTI) || (ifmod == IF_LORA_STD)) { - DEBUG_MSG("Note: Lora packet\n"); - if ((buff[s+1] & 0x01) == 1) { /* CRC enabled */ - if (stat_fifo == 1) { - p->status = STAT_CRC_OK; - } else if (stat_fifo == 3){ - p->status = STAT_CRC_BAD; - } else { - p->status = STAT_UNDEFINED; - } - } else { - p->status = STAT_NO_CRC; - } - p->modulation = MOD_LORA; - p->snr = ((double)((int8_t)buff[s+2]))/4; - p->snr_min = ((double)((int8_t)buff[s+3]))/4; - p->snr_max = ((double)((int8_t)buff[s+4]))/4; - if (ifmod == IF_LORA_MULTI) { - p->rssi = RSSI_OFFSET_LORA_MULTI + (double)buff[s+5]; //TODO: check formula - p->bandwidth = BW_125KHZ; /* fixed in hardware */ - } else { - p->rssi = RSSI_OFFSET_LORA_STD + (double)buff[s+5]; //TODO: check formula, might depend on bandwidth - p->bandwidth = BW_UNDEFINED; // TODO: get parameter from config - } - switch ((buff[s+1] >> 4) & 0x0F) { - case 7: p->datarate = DR_LORA_SF7; break; - case 8: p->datarate = DR_LORA_SF8; break; - case 9: p->datarate = DR_LORA_SF9; break; - case 10: p->datarate = DR_LORA_SF10; break; - case 11: p->datarate = DR_LORA_SF11; break; - case 12: p->datarate = DR_LORA_SF12; break; - default: p->datarate = DR_UNDEFINED; - } - switch ((buff[s+1] >> 1) & 0x07) { - case 1: p->coderate = CR_LORA_4_5; break; - case 2: p->coderate = CR_LORA_4_6; break; - case 3: p->coderate = CR_LORA_4_7; break; - case 4: p->coderate = CR_LORA_4_8; break; - default: p->coderate = CR_UNDEFINED; - } - } else if (ifmod == IF_FSK_STD) { - DEBUG_MSG("Note: FSK packet\n"); - p->status = STAT_UNDEFINED; // TODO - p->modulation = MOD_FSK; - p->rssi = NAN; // TODO - p->snr = NAN; - p->snr_min = NAN; - p->snr_max = NAN; - p->bandwidth = BW_UNDEFINED; // TODO - p->datarate = DR_UNDEFINED; // TODO - p->coderate = CR_UNDEFINED; // TODO - } else { - DEBUG_MSG("ERROR: UNEXPECTED PACKET ORIGIN\n"); - p->status = STAT_UNDEFINED; - p->modulation = MOD_UNDEFINED; - p->rssi = NAN; - p->snr = NAN; - p->snr_min = NAN; - p->snr_max = NAN; - p->bandwidth = BW_UNDEFINED; - p->datarate = DR_UNDEFINED; - p->coderate = CR_UNDEFINED; - } - - p->count_us = (uint32_t)buff[s+6] + ((uint32_t)buff[s+7] << 8) + ((uint32_t)buff[s+8] << 16) + ((uint32_t)buff[s+9] << 24); - p->crc = (uint16_t)buff[s+10] + ((uint16_t)buff[s+11] << 8); - - /* advance packet FIFO */ - lgw_reg_w(LGW_RX_PACKET_DATA_FIFO_NUM_STORED, 0); - } - - return nb_pkt_fetch; + int nb_pkt_fetch; /* loop variable and return value */ + struct lgw_pkt_rx_s *p; /* pointer to the current structure in the struct array */ + uint8_t buff[255+RX_METADATA_NB]; /* buffer to store the result of SPI read bursts */ + uint16_t data_addr; /* address read from the FIFO and programmed before the data buffer read operation */ + int s; /* size of the payload, uses to address metadata */ + int ifmod; /* type of if_chain/modem a packet was received by */ + int stat_fifo; /* the packet status as indicated in the FIFO */ + int j; + + /* check if the gateway is running */ + if (lgw_is_started == false) { + DEBUG_MSG("ERROR: GATEWAY IS NOT RUNNING, START IT BEFORE RECEIVING\n"); + return LGW_HAL_ERROR; + } + + /* check input variables */ + if (max_pkt <= 0) { + DEBUG_PRINTF("ERROR: %d = INVALID MAX NUMBER OF PACKETS TO FETCH\n", max_pkt); + return LGW_HAL_ERROR; + } + CHECK_NULL(pkt_data); + + /* iterate max_pkt times at most */ + for (nb_pkt_fetch = 0; nb_pkt_fetch < max_pkt; ++nb_pkt_fetch) { + + /* point to the proper struct in the struct array */ + p = &pkt_data[nb_pkt_fetch]; + + /* fetch all the RX FIFO data */ + lgw_reg_rb(LGW_RX_PACKET_DATA_FIFO_NUM_STORED, buff, 5); + + /* how many packets are in the RX buffer ? Break if zero */ + if (buff[0] == 0) { + DEBUG_MSG("Note: RX packet buffer empty, receive function returning nothing\n"); + break; /* no more packets to fetch, exit out of FOR loop */ + } + + DEBUG_PRINTF("FIFO content: %x %x %x %x %x\n",buff[0],buff[1],buff[2],buff[3],buff[4]); + + p->size = buff[4]; + s = p->size; + stat_fifo = buff[3]; /* will be used later, need to save it before overwriting buff */ + + /* STILL required */ + data_addr = (uint16_t)buff[1] + ((uint16_t)buff[2] << 8); + lgw_reg_w(LGW_RX_DATA_BUF_ADDR, data_addr); + + /* dynamically allocate memory to store payload */ + p->payload = (uint8_t *)malloc(s); + if (p->payload == NULL) { + /* not enough memory to allocate for payload, abort with error */ + DEBUG_MSG("ERROR: IMPOSSIBLE TO ALLOCATE MEMORY TO FETCH PAYLOAD\n"); + return LGW_HAL_ERROR; + } + + /* get payload + metadata */ + lgw_reg_rb(LGW_RX_DATA_BUF_DATA, buff, s+RX_METADATA_NB); + + /* copy payload */ + memcpy(p->payload, buff, s); + + /* process metadata */ + p->if_chain = buff[s+0]; + ifmod = ifmod_config[p->if_chain]; + DEBUG_PRINTF("[%d %d]\n", p->if_chain, ifmod); + + if ((ifmod == IF_LORA_MULTI) || (ifmod == IF_LORA_STD)) { + DEBUG_MSG("Note: Lora packet\n"); + if ((buff[s+1] & 0x01) == 1) { /* CRC enabled */ + if (stat_fifo == 1) { + p->status = STAT_CRC_OK; + } else if (stat_fifo == 3){ + p->status = STAT_CRC_BAD; + } else { + p->status = STAT_UNDEFINED; + } + } else { + p->status = STAT_NO_CRC; + } + p->modulation = MOD_LORA; + p->snr = ((float)((int8_t)buff[s+2]))/4; + p->snr_min = ((float)((int8_t)buff[s+3]))/4; + p->snr_max = ((float)((int8_t)buff[s+4]))/4; + if (ifmod == IF_LORA_MULTI) { + p->rssi = RSSI_OFFSET_LORA_MULTI + (float)buff[s+5]; //TODO: check formula + p->bandwidth = BW_125KHZ; /* fixed in hardware */ + } else { + p->rssi = RSSI_OFFSET_LORA_STD + (float)buff[s+5]; //TODO: check formula, might depend on bandwidth + p->bandwidth = lora_rx_bw; /* get the parameter from the config variable */ + } + switch ((buff[s+1] >> 4) & 0x0F) { + case 7: p->datarate = DR_LORA_SF7; break; + case 8: p->datarate = DR_LORA_SF8; break; + case 9: p->datarate = DR_LORA_SF9; break; + case 10: p->datarate = DR_LORA_SF10; break; + case 11: p->datarate = DR_LORA_SF11; break; + case 12: p->datarate = DR_LORA_SF12; break; + default: p->datarate = DR_UNDEFINED; + } + switch ((buff[s+1] >> 1) & 0x07) { + case 1: p->coderate = CR_LORA_4_5; break; + case 2: p->coderate = CR_LORA_4_6; break; + case 3: p->coderate = CR_LORA_4_7; break; + case 4: p->coderate = CR_LORA_4_8; break; + default: p->coderate = CR_UNDEFINED; + } + } else if (ifmod == IF_FSK_STD) { + // TODO: process received FSK packets + DEBUG_MSG("Note: FSK packet\n"); + p->status = STAT_UNDEFINED; + p->modulation = MOD_FSK; + p->rssi = NAN; + p->snr = NAN; + p->snr_min = NAN; + p->snr_max = NAN; + p->bandwidth = BW_UNDEFINED; + p->datarate = DR_UNDEFINED; + p->coderate = CR_UNDEFINED; + } else { + DEBUG_MSG("ERROR: UNEXPECTED PACKET ORIGIN\n"); + p->status = STAT_UNDEFINED; + p->modulation = MOD_UNDEFINED; + p->rssi = NAN; + p->snr = NAN; + p->snr_min = NAN; + p->snr_max = NAN; + p->bandwidth = BW_UNDEFINED; + p->datarate = DR_UNDEFINED; + p->coderate = CR_UNDEFINED; + } + + p->count_us = (uint32_t)buff[s+6] + ((uint32_t)buff[s+7] << 8) + ((uint32_t)buff[s+8] << 16) + ((uint32_t)buff[s+9] << 24); + p->crc = (uint16_t)buff[s+10] + ((uint16_t)buff[s+11] << 8); + + /* advance packet FIFO */ + lgw_reg_w(LGW_RX_PACKET_DATA_FIFO_NUM_STORED, 0); + } + + return nb_pkt_fetch; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_send(struct lgw_pkt_tx_s pkt_data) { - uint8_t buff[255+TX_METADATA_NB]; /* buffer to prepare the packet to send + metadata before SPI write burst */ - uint32_t part_int; /* integer part for PLL register value calculation */ - uint32_t part_frac; /* fractional part for PLL register value calculation */ - int i; - - /* check if the gateway is running */ - if (lgw_is_started == false) { - DEBUG_MSG("ERROR: GATEWAY IS NOT RUNNING, START IT BEFORE SENDING\n"); - return LGW_HAL_ERROR; - } - - /* check input variables */ - CHECK_NULL(pkt_data.payload); - if (pkt_data.rf_chain >= LGW_RF_CHAIN_NB) { - DEBUG_MSG("ERROR: INVALID RF_CHAIN TO SEND PACKETS\n"); - return LGW_HAL_ERROR; - } - if (rf_enable[pkt_data.rf_chain] == false) { - DEBUG_MSG("ERROR: SELECTED RF_CHAIN IS DISABLED\n"); - return LGW_HAL_ERROR; - } - if (pkt_data.freq_hz > rf_tx_upfreq[pkt_data.rf_chain]) { - DEBUG_PRINTF("ERROR: FREQUENCY %d HIGHER THAN UPPER LIMIT %d OF RF_CHAIN %d\n", pkt_data.freq_hz, rf_tx_upfreq[pkt_data.rf_chain], pkt_data.rf_chain); - return LGW_HAL_ERROR; - } else if (pkt_data.freq_hz < rf_tx_lowfreq[pkt_data.rf_chain]) { - DEBUG_PRINTF("ERROR: FREQUENCY %d LOWER THAN LOWER LIMIT %d OF RF_CHAIN %d\n", pkt_data.freq_hz, rf_tx_lowfreq[pkt_data.rf_chain], pkt_data.rf_chain); - return LGW_HAL_ERROR; - } - i = pkt_data.tx_mode; - if ((i != IMMEDIATE) && (i != TIMESTAMPED) && (i != ON_GPS)) { - DEBUG_MSG("ERROR: TX_MODE NOT SUPPORTED\n"); - return LGW_HAL_ERROR; - } - if (pkt_data.modulation == MOD_LORA) { - i = pkt_data.bandwidth; - if ((i != BW_125KHZ) && (i != BW_250KHZ) && (i != BW_500KHZ)) { - DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA TX\n"); - return LGW_HAL_ERROR; - } - i = pkt_data.datarate; - if ((i!=DR_LORA_SF7)&&(i!=DR_LORA_SF8)&&(i!=DR_LORA_SF9)&&(i!=DR_LORA_SF10)&&(i!=DR_LORA_SF11)&&(i!=DR_LORA_SF12)) { - DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY LORA TX\n"); - return LGW_HAL_ERROR; - } - i = pkt_data.coderate; - if ((i != CR_LORA_4_5) && (i != CR_LORA_4_6) && (i != CR_LORA_4_7) && (i != CR_LORA_4_8)) { - DEBUG_MSG("ERROR: CODERATE NOT SUPPORTED BY LORA TX\n"); - return LGW_HAL_ERROR; - } - if (pkt_data.size > 255) { - DEBUG_MSG("ERROR: PAYLOAD LENGTH TOO BIG FOR LORA TX\n"); - return LGW_HAL_ERROR; - } - }else if ((pkt_data.modulation == MOD_FSK) || (pkt_data.modulation == MOD_GFSK)) { - DEBUG_MSG("ERROR: (G)FSK TX MODULATION NOT SUPPORTED YET\n"); - return LGW_HAL_ERROR; - } else { - DEBUG_MSG("ERROR: INVALID TX MODULATION\n"); - return LGW_HAL_ERROR; - } - - /* metadata 0 to 2, TX PLL frequency */ - part_int = pkt_data.freq_hz / LGW_SW1257_DENUM; /* integer part, gives the MSB and the middle byte */ - part_frac = ((pkt_data.freq_hz % LGW_SW1257_DENUM) << 8) / LGW_SW1257_DENUM; /* fractional part, gives LSB */ - buff[0] = 0xFF & (part_int >> 8); /* Most Significant Byte */ - buff[1] = 0xFF & part_int; /* middle byte */ - buff[2] = 0xFF & part_frac; /* Least Significant Byte */ - - /* metadata 3 to 6, timestamp trigger value */ - buff[3] = 0xFF & (pkt_data.count_us >> 24); - buff[4] = 0xFF & (pkt_data.count_us >> 16); - buff[5] = 0xFF & (pkt_data.count_us >> 8); - buff[6] = 0xFF & pkt_data.count_us; - - /* parameters depending on modulation */ - if (pkt_data.modulation == MOD_LORA) { - /* metadata 7, modulation type, radio chain selection and TX power */ - buff[7] = (0x20 & (pkt_data.rf_chain << 5)) | (0x0F & pkt_data.rf_power); /* bit 4 is 0 -> Lora modulation */ - /* fine control over TX power not supported yet, any value other than 8 is 14 dBm */ - - buff[8] = 0; /* metadata 8, not used */ - - /* metadata 9, CRC, Lora CR & SF */ - switch (pkt_data.datarate) { - case DR_LORA_SF7: buff[9] |= 7; break; - case DR_LORA_SF8: buff[9] |= 8; break; - case DR_LORA_SF9: buff[9] |= 9; break; - case DR_LORA_SF10: buff[9] |= 10; break; - case DR_LORA_SF11: buff[9] |= 11; break; - case DR_LORA_SF12: buff[9] |= 12; break; - default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.datarate); - } - switch (pkt_data.coderate) { - case CR_LORA_4_5: buff[9] |= 1 << 4; break; - case CR_LORA_4_6: buff[9] |= 2 << 4; break; - case CR_LORA_4_7: buff[9] |= 3 << 4; break; - case CR_LORA_4_8: buff[9] |= 4 << 4; break; - default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.coderate); - } - if (pkt_data.no_crc == false) { - buff[9] |= 0x80; /* set 'CRC enable' bit */ - } - - /* metadata 10, payload size */ - buff[10] = pkt_data.size; - - /* metadata 11, implicit header & modulation bandwidth */ - switch (pkt_data.bandwidth) { - case BW_125KHZ: buff[11] |= 0; break; - case BW_250KHZ: buff[11] |= 1; break; - case BW_500KHZ: buff[11] |= 2; break; - default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.bandwidth); - } - if (pkt_data.no_header == true) { - buff[11] |= 0x04; /* set 'implicit header' bit */ - } - - /* metadata 12 & 13, Lora preamble size */ - if (pkt_data.preamble < MIN_LORA_PREAMBLE) { /* enforce minimum preamble size */ - pkt_data.preamble = MIN_LORA_PREAMBLE; - DEBUG_MSG("Note: preamble length adjusted to respect minimum Lora preamble size\n"); - } - buff[12] = 0xFF & (pkt_data.preamble >> 8); - buff[13] = 0xFF & pkt_data.preamble; - - /* metadata 14 & 15, not used */ - buff[14] = 0; - buff[15] = 0; - - } else { - DEBUG_MSG("ERROR: ONLY LORA TX SUPPORTED FOR NOW\n"); - return LGW_HAL_ERROR; - } - - /* copy payload */ - for (i = 0; i < pkt_data.size; ++i) { - buff[i+TX_METADATA_NB] = pkt_data.payload[i]; - } - - /* put metadata + payload in the TX data buffer */ - lgw_reg_w(LGW_TX_DATA_BUF_ADDR, 0); - lgw_reg_wb(LGW_TX_DATA_BUF_DATA, buff, (pkt_data.size + TX_METADATA_NB)); - DEBUG_ARRAY(i, pkt_data.size+TX_METADATA_NB, buff); - - /* send data */ - switch(pkt_data.tx_mode) { - case IMMEDIATE: - lgw_reg_w(LGW_TX_TRIG_IMMEDIATE, 0); - lgw_reg_w(LGW_TX_TRIG_IMMEDIATE, 1); - break; - - case TIMESTAMPED: - lgw_reg_w(LGW_TX_TRIG_DELAYED, 0); - lgw_reg_w(LGW_TX_TRIG_DELAYED, 1); - break; - - case ON_GPS: - lgw_reg_w(LGW_TX_TRIG_GPS, 0); - lgw_reg_w(LGW_TX_TRIG_GPS, 1); - break; - - default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.tx_mode); - } - - return LGW_HAL_SUCCESS; + uint8_t buff[255+TX_METADATA_NB]; /* buffer to prepare the packet to send + metadata before SPI write burst */ + uint32_t part_int; /* integer part for PLL register value calculation */ + uint32_t part_frac; /* fractional part for PLL register value calculation */ + int i; + + /* check if the gateway is running */ + if (lgw_is_started == false) { + DEBUG_MSG("ERROR: GATEWAY IS NOT RUNNING, START IT BEFORE SENDING\n"); + return LGW_HAL_ERROR; + } + + /* check input variables */ + CHECK_NULL(pkt_data.payload); + if (pkt_data.rf_chain >= LGW_RF_CHAIN_NB) { + DEBUG_MSG("ERROR: INVALID RF_CHAIN TO SEND PACKETS\n"); + return LGW_HAL_ERROR; + } + if (rf_enable[pkt_data.rf_chain] == false) { + DEBUG_MSG("ERROR: SELECTED RF_CHAIN IS DISABLED\n"); + return LGW_HAL_ERROR; + } + if (pkt_data.freq_hz > rf_tx_upfreq[pkt_data.rf_chain]) { + DEBUG_PRINTF("ERROR: FREQUENCY %d HIGHER THAN UPPER LIMIT %d OF RF_CHAIN %d\n", pkt_data.freq_hz, rf_tx_upfreq[pkt_data.rf_chain], pkt_data.rf_chain); + return LGW_HAL_ERROR; + } else if (pkt_data.freq_hz < rf_tx_lowfreq[pkt_data.rf_chain]) { + DEBUG_PRINTF("ERROR: FREQUENCY %d LOWER THAN LOWER LIMIT %d OF RF_CHAIN %d\n", pkt_data.freq_hz, rf_tx_lowfreq[pkt_data.rf_chain], pkt_data.rf_chain); + return LGW_HAL_ERROR; + } + i = pkt_data.tx_mode; + if ((i != IMMEDIATE) && (i != TIMESTAMPED) && (i != ON_GPS)) { + DEBUG_MSG("ERROR: TX_MODE NOT SUPPORTED\n"); + return LGW_HAL_ERROR; + } + if (pkt_data.modulation == MOD_LORA) { + i = pkt_data.bandwidth; + if ((i != BW_125KHZ) && (i != BW_250KHZ) && (i != BW_500KHZ)) { + DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA TX\n"); + return LGW_HAL_ERROR; + } + i = pkt_data.datarate; + if ((i!=DR_LORA_SF7)&&(i!=DR_LORA_SF8)&&(i!=DR_LORA_SF9)&&(i!=DR_LORA_SF10)&&(i!=DR_LORA_SF11)&&(i!=DR_LORA_SF12)) { + DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY LORA TX\n"); + return LGW_HAL_ERROR; + } + i = pkt_data.coderate; + if ((i != CR_LORA_4_5) && (i != CR_LORA_4_6) && (i != CR_LORA_4_7) && (i != CR_LORA_4_8)) { + DEBUG_MSG("ERROR: CODERATE NOT SUPPORTED BY LORA TX\n"); + return LGW_HAL_ERROR; + } + if (pkt_data.size > 255) { + DEBUG_MSG("ERROR: PAYLOAD LENGTH TOO BIG FOR LORA TX\n"); + return LGW_HAL_ERROR; + } + }else if ((pkt_data.modulation == MOD_FSK) || (pkt_data.modulation == MOD_GFSK)) { + DEBUG_MSG("ERROR: (G)FSK TX MODULATION NOT SUPPORTED YET\n"); + return LGW_HAL_ERROR; + } else { + DEBUG_MSG("ERROR: INVALID TX MODULATION\n"); + return LGW_HAL_ERROR; + } + + /* metadata 0 to 2, TX PLL frequency */ + part_int = pkt_data.freq_hz / LGW_SX1257_DENOMINATOR; /* integer part, gives the MSB and the middle byte */ + part_frac = ((pkt_data.freq_hz % LGW_SX1257_DENOMINATOR) << 8) / LGW_SX1257_DENOMINATOR; /* fractional part, gives LSB */ + buff[0] = 0xFF & (part_int >> 8); /* Most Significant Byte */ + buff[1] = 0xFF & part_int; /* middle byte */ + buff[2] = 0xFF & part_frac; /* Least Significant Byte */ + + /* metadata 3 to 6, timestamp trigger value */ + buff[3] = 0xFF & (pkt_data.count_us >> 24); + buff[4] = 0xFF & (pkt_data.count_us >> 16); + buff[5] = 0xFF & (pkt_data.count_us >> 8); + buff[6] = 0xFF & pkt_data.count_us; + + /* parameters depending on modulation */ + if (pkt_data.modulation == MOD_LORA) { + /* metadata 7, modulation type, radio chain selection and TX power */ + buff[7] = (0x20 & (pkt_data.rf_chain << 5)) | (0x0F & pkt_data.rf_power); /* bit 4 is 0 -> Lora modulation */ + /* fine control over TX power not supported yet, any value other than 8 is 14 dBm */ + + buff[8] = 0; /* metadata 8, not used */ + + /* metadata 9, CRC, Lora CR & SF */ + switch (pkt_data.datarate) { + case DR_LORA_SF7: buff[9] |= 7; break; + case DR_LORA_SF8: buff[9] |= 8; break; + case DR_LORA_SF9: buff[9] |= 9; break; + case DR_LORA_SF10: buff[9] |= 10; break; + case DR_LORA_SF11: buff[9] |= 11; break; + case DR_LORA_SF12: buff[9] |= 12; break; + default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.datarate); + } + switch (pkt_data.coderate) { + case CR_LORA_4_5: buff[9] |= 1 << 4; break; + case CR_LORA_4_6: buff[9] |= 2 << 4; break; + case CR_LORA_4_7: buff[9] |= 3 << 4; break; + case CR_LORA_4_8: buff[9] |= 4 << 4; break; + default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.coderate); + } + if (pkt_data.no_crc == false) { + buff[9] |= 0x80; /* set 'CRC enable' bit */ + } + + /* metadata 10, payload size */ + buff[10] = pkt_data.size; + + /* metadata 11, implicit header & modulation bandwidth */ + switch (pkt_data.bandwidth) { + case BW_125KHZ: buff[11] |= 0; break; + case BW_250KHZ: buff[11] |= 1; break; + case BW_500KHZ: buff[11] |= 2; break; + default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.bandwidth); + } + if (pkt_data.no_header == true) { + buff[11] |= 0x04; /* set 'implicit header' bit */ + } + + /* metadata 12 & 13, Lora preamble size */ + if (pkt_data.preamble < MIN_LORA_PREAMBLE) { /* enforce minimum preamble size */ + pkt_data.preamble = MIN_LORA_PREAMBLE; + DEBUG_MSG("Note: preamble length adjusted to respect minimum Lora preamble size\n"); + } + buff[12] = 0xFF & (pkt_data.preamble >> 8); + buff[13] = 0xFF & pkt_data.preamble; + + /* metadata 14 & 15, not used */ + buff[14] = 0; + buff[15] = 0; + + /* setting TX polarity */ + if (pkt_data.invert_pol == false) { + lgw_reg_w(LGW_TX_SWAP_IQ,1); /* configure TX in "normal" polarity */ + } else { + lgw_reg_w(LGW_TX_SWAP_IQ,0); /* configure TX in "orthogonal" polarity */ + } + } else { + DEBUG_MSG("ERROR: ONLY LORA TX SUPPORTED FOR NOW\n"); + return LGW_HAL_ERROR; + } + + /* copy payload */ + memcpy((void *)(buff + TX_METADATA_NB), pkt_data.payload, pkt_data.size); + + /* put metadata + payload in the TX data buffer */ + lgw_reg_w(LGW_TX_DATA_BUF_ADDR, 0); + lgw_reg_wb(LGW_TX_DATA_BUF_DATA, buff, (pkt_data.size + TX_METADATA_NB)); + DEBUG_ARRAY(i, pkt_data.size+TX_METADATA_NB, buff); + + /* send data */ + switch(pkt_data.tx_mode) { + case IMMEDIATE: + lgw_reg_w(LGW_TX_TRIG_IMMEDIATE, 0); + lgw_reg_w(LGW_TX_TRIG_IMMEDIATE, 1); + break; + + case TIMESTAMPED: + lgw_reg_w(LGW_TX_TRIG_DELAYED, 0); + lgw_reg_w(LGW_TX_TRIG_DELAYED, 1); + break; + + case ON_GPS: + lgw_reg_w(LGW_TX_TRIG_GPS, 0); + lgw_reg_w(LGW_TX_TRIG_GPS, 1); + break; + + default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.tx_mode); + } + + return LGW_HAL_SUCCESS; } /* --- EOF ------------------------------------------------------------------ */ diff --git a/loragw_hal/src/loragw_reg.c b/loragw_hal/src/loragw_reg.c index a2a3f79..3026f50 100644 --- a/loragw_hal/src/loragw_reg.c +++ b/loragw_hal/src/loragw_reg.c @@ -1,25 +1,25 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - Functions used to handle a single Lora gateway. - Registers are addressed by name. - Multi-bytes registers are handled automatically. - Read-modify-write is handled automatically. + Functions used to handle a single Lora gateway. + Registers are addressed by name. + Multi-bytes registers are handled automatically. + Read-modify-write is handled automatically. */ /* -------------------------------------------------------------------------- */ /* --- DEPENDANCIES --------------------------------------------------------- */ -#include <stdint.h> /* C99 types */ -#include <stdbool.h> /* bool type */ -#include <stdio.h> /* printf fprintf */ +#include <stdint.h> /* C99 types */ +#include <stdbool.h> /* bool type */ +#include <stdio.h> /* printf fprintf */ #include "loragw_spi.h" #include "loragw_reg.h" @@ -29,332 +29,332 @@ Description: #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #ifdef DEBUG - #define DEBUG_MSG(str) fprintf(stderr, str) - #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) - #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;} + #define DEBUG_MSG(str) fprintf(stderr, str) + #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) + #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;} #else - #define DEBUG_MSG(str) - #define DEBUG_PRINTF(fmt, args...) - #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;} + #define DEBUG_MSG(str) + #define DEBUG_PRINTF(fmt, args...) + #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;} #endif /* -------------------------------------------------------------------------- */ /* --- PRIVATE TYPES -------------------------------------------------------- */ struct lgw_reg_s { - int8_t page; /*!< page containing the register (-1 for all pages) */ - uint8_t addr; /*!< base address of the register (7 bit) */ - uint8_t offs; /*!< position of the register LSB (between 0 to 7) */ - bool sign; /*!< 1 indicates the register is signed (2 complem.) */ - uint8_t leng; /*!< number of bits in the register */ - char name[40]; /*!< name of the register */ - bool rdon; /*!< 1 indicates a read-only register */ - int32_t dflt; /*!< register default value */ + int8_t page; /*!< page containing the register (-1 for all pages) */ + uint8_t addr; /*!< base address of the register (7 bit) */ + uint8_t offs; /*!< position of the register LSB (between 0 to 7) */ + bool sign; /*!< 1 indicates the register is signed (2 complem.) */ + uint8_t leng; /*!< number of bits in the register */ + char name[40]; /*!< name of the register */ + bool rdon; /*!< 1 indicates a read-only register */ + int32_t dflt; /*!< register default value */ }; /* -------------------------------------------------------------------------- */ /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ -#define PAGE_ADDR 0x00 -#define PAGE_MASK 0x03 +#define PAGE_ADDR 0x00 +#define PAGE_MASK 0x03 /* auto generated register mapping for C code : 24-Jun-2013 20:29:09 -this file contains autogenerated C struct used to access the LORA register from the Primer firmware +this file contains autogenerated C struct used to access the Lora register from the Primer firmware this file is autogenerated from registers description 290 registers are defined */ const struct lgw_reg_s loregs[LGW_TOTALREGS] = { - {-1,0,0,0,2,"PAGE_REG",0,0}, - {-1,0,7,0,1,"SOFT_RESET",0,0}, - {-1,1,0,0,8,"VERSION",1,100}, - {-1,2,0,0,16,"RX_DATA_BUF_ADDR",0,0}, - {-1,4,0,0,8,"RX_DATA_BUF_DATA",1,0}, - {-1,5,0,0,8,"TX_DATA_BUF_ADDR",0,0}, - {-1,6,0,0,8,"TX_DATA_BUF_DATA",0,0}, - {-1,7,0,0,8,"CAPTURE_RAM_ADDR",0,0}, - {-1,8,0,0,8,"CAPTURE_RAM_DATA",1,0}, - {-1,9,0,0,8,"MCU_PROM_ADDR",0,0}, - {-1,10,0,0,8,"MCU_PROM_DATA",0,0}, - {-1,11,0,0,8,"RX_PACKET_DATA_FIFO_NUM_STORED",0,0}, - {-1,12,0,0,16,"RX_PACKET_DATA_FIFO_ADDR_POINTER",1,0}, - {-1,14,0,0,8,"RX_PACKET_DATA_FIFO_STATUS",1,0}, - {-1,15,0,0,8,"RX_PACKET_DATA_FIFO_PAYLOAD_SIZE",1,0}, - {-1,16,0,0,1,"MBWSSF_MODEM_ENABLE",0,0}, - {-1,16,1,0,1,"CONCENTRATOR_MODEM_ENABLE",0,0}, - {-1,16,2,0,1,"FSK_MODEM_ENABLE",0,0}, - {-1,17,0,0,1,"CLK32M_EN",0,0}, - {-1,17,1,0,1,"CLKHS_EN",0,0}, - {-1,18,0,0,1,"START_BIST0",0,0}, - {-1,18,1,0,1,"START_BIST1",0,0}, - {-1,18,2,0,1,"CLEAR_BIST0",0,0}, - {-1,18,3,0,1,"CLEAR_BIST1",0,0}, - {-1,19,0,0,1,"BIST0_FINISHED",1,0}, - {-1,19,1,0,1,"BIST1_FINISHED",1,0}, - {-1,20,0,0,1,"MCU_AGC_PROG_RAM_BIST_STATUS",1,0}, - {-1,20,1,0,1,"MCU_ARB_PROG_RAM_BIST_STATUS",1,0}, - {-1,20,2,0,1,"CAPTURE_RAM_BIST_STATUS",1,0}, - {-1,20,3,0,1,"CHAN_FIR_RAM0_BIST_STATUS",1,0}, - {-1,20,4,0,1,"CHAN_FIR_RAM1_BIST_STATUS",1,0}, - {-1,21,0,0,1,"CORR0_RAM_BIST_STATUS",1,0}, - {-1,21,1,0,1,"CORR1_RAM_BIST_STATUS",1,0}, - {-1,21,2,0,1,"CORR2_RAM_BIST_STATUS",1,0}, - {-1,21,3,0,1,"CORR3_RAM_BIST_STATUS",1,0}, - {-1,21,4,0,1,"CORR4_RAM_BIST_STATUS",1,0}, - {-1,21,5,0,1,"CORR5_RAM_BIST_STATUS",1,0}, - {-1,21,6,0,1,"CORR6_RAM_BIST_STATUS",1,0}, - {-1,21,7,0,1,"CORR7_RAM_BIST_STATUS",1,0}, - {-1,22,0,0,1,"MODEM0_RAM0_BIST_STATUS",1,0}, - {-1,22,1,0,1,"MODEM1_RAM0_BIST_STATUS",1,0}, - {-1,22,2,0,1,"MODEM2_RAM0_BIST_STATUS",1,0}, - {-1,22,3,0,1,"MODEM3_RAM0_BIST_STATUS",1,0}, - {-1,22,4,0,1,"MODEM4_RAM0_BIST_STATUS",1,0}, - {-1,22,5,0,1,"MODEM5_RAM0_BIST_STATUS",1,0}, - {-1,22,6,0,1,"MODEM6_RAM0_BIST_STATUS",1,0}, - {-1,22,7,0,1,"MODEM7_RAM0_BIST_STATUS",1,0}, - {-1,23,0,0,1,"MODEM0_RAM1_BIST_STATUS",1,0}, - {-1,23,1,0,1,"MODEM1_RAM1_BIST_STATUS",1,0}, - {-1,23,2,0,1,"MODEM2_RAM1_BIST_STATUS",1,0}, - {-1,23,3,0,1,"MODEM3_RAM1_BIST_STATUS",1,0}, - {-1,23,4,0,1,"MODEM4_RAM1_BIST_STATUS",1,0}, - {-1,23,5,0,1,"MODEM5_RAM1_BIST_STATUS",1,0}, - {-1,23,6,0,1,"MODEM6_RAM1_BIST_STATUS",1,0}, - {-1,23,7,0,1,"MODEM7_RAM1_BIST_STATUS",1,0}, - {-1,24,0,0,1,"MODEM0_RAM2_BIST_STATUS",1,0}, - {-1,24,1,0,1,"MODEM1_RAM2_BIST_STATUS",1,0}, - {-1,24,2,0,1,"MODEM2_RAM2_BIST_STATUS",1,0}, - {-1,24,3,0,1,"MODEM3_RAM2_BIST_STATUS",1,0}, - {-1,24,4,0,1,"MODEM4_RAM2_BIST_STATUS",1,0}, - {-1,24,5,0,1,"MODEM5_RAM2_BIST_STATUS",1,0}, - {-1,24,6,0,1,"MODEM6_RAM2_BIST_STATUS",1,0}, - {-1,24,7,0,1,"MODEM7_RAM2_BIST_STATUS",1,0}, - {-1,25,0,0,1,"MODEM_MBWSSF_RAM0_BIST_STATUS",1,0}, - {-1,25,1,0,1,"MODEM_MBWSSF_RAM1_BIST_STATUS",1,0}, - {-1,25,2,0,1,"MODEM_MBWSSF_RAM2_BIST_STATUS",1,0}, - {-1,26,0,0,1,"MCU_AGC_DATA_RAM_BIST0_STATUS",1,0}, - {-1,26,1,0,1,"MCU_AGC_DATA_RAM_BIST1_STATUS",1,0}, - {-1,26,2,0,1,"MCU_ARB_DATA_RAM_BIST0_STATUS",1,0}, - {-1,26,3,0,1,"MCU_ARB_DATA_RAM_BIST1_STATUS",1,0}, - {-1,26,4,0,1,"TX_TOP_RAM_BIST0_STATUS",1,0}, - {-1,26,5,0,1,"TX_TOP_RAM_BIST1_STATUS",1,0}, - {-1,26,6,0,1,"DATA_MNGT_RAM_BIST0_STATUS",1,0}, - {-1,26,7,0,1,"DATA_MNGT_RAM_BIST1_STATUS",1,0}, - {-1,27,0,0,8,"GPIO_SELECT",0,0}, - {-1,28,0,0,8,"GPIO_MUX",0,0}, - {-1,127,0,0,1,"EMERGENCY_FORCE_HOST_CTRL",0,0}, - {0,29,0,0,1,"RX_INVERT_IQ",0,0}, - {0,29,1,0,1,"MODEM_INVERT_IQ",0,1}, - {0,29,2,0,1,"MBWSSF_MODEM_INVERT_IQ",0,0}, - {0,29,3,0,1,"RX_EDGE_SELECT",0,0}, - {0,29,4,0,1,"MISC_RADIO_EN",0,0}, - {0,30,0,0,4,"FILTER_GAIN",0,7}, - {0,31,0,0,8,"RADIO_SELECT",0,240}, - {0,32,0,1,13,"IF_FREQ_0",0,-384}, - {0,34,0,1,13,"IF_FREQ_1",0,-128}, - {0,36,0,1,13,"IF_FREQ_2",0,128}, - {0,38,0,1,13,"IF_FREQ_3",0,384}, - {0,40,0,1,13,"IF_FREQ_4",0,-384}, - {0,42,0,1,13,"IF_FREQ_5",0,-128}, - {0,44,0,1,13,"IF_FREQ_6",0,128}, - {0,46,0,1,13,"IF_FREQ_7",0,384}, - {0,48,0,1,13,"IF_FREQ_8",0,0}, - {0,50,0,1,13,"IF_FREQ_9",0,0}, - {0,60,0,0,1,"CHANN_OVERRIDE_AGC_GAIN",0,0}, - {0,60,1,0,4,"CHANN_AGC_GAIN",0,7}, - {0,61,0,0,7,"CORR0_DETECT_EN",0,0}, - {0,62,0,0,7,"CORR1_DETECT_EN",0,0}, - {0,63,0,0,7,"CORR2_DETECT_EN",0,0}, - {0,64,0,0,7,"CORR3_DETECT_EN",0,0}, - {0,65,0,0,7,"CORR4_DETECT_EN",0,0}, - {0,66,0,0,7,"CORR5_DETECT_EN",0,0}, - {0,67,0,0,7,"CORR6_DETECT_EN",0,0}, - {0,68,0,0,7,"CORR7_DETECT_EN",0,0}, - {0,69,0,0,1,"CORR_SAME_PEAKS_OPTION_SF6",0,0}, - {0,69,1,0,1,"CORR_SAME_PEAKS_OPTION_SF7",0,1}, - {0,69,2,0,1,"CORR_SAME_PEAKS_OPTION_SF8",0,1}, - {0,69,3,0,1,"CORR_SAME_PEAKS_OPTION_SF9",0,1}, - {0,69,4,0,1,"CORR_SAME_PEAKS_OPTION_SF10",0,1}, - {0,69,5,0,1,"CORR_SAME_PEAKS_OPTION_SF11",0,1}, - {0,69,6,0,1,"CORR_SAME_PEAKS_OPTION_SF12",0,1}, - {0,70,0,0,4,"CORR_SIG_NOISE_RATIO_SF6",0,4}, - {0,70,4,0,4,"CORR_SIG_NOISE_RATIO_SF7",0,4}, - {0,71,0,0,4,"CORR_SIG_NOISE_RATIO_SF8",0,4}, - {0,71,4,0,4,"CORR_SIG_NOISE_RATIO_SF9",0,4}, - {0,72,0,0,4,"CORR_SIG_NOISE_RATIO_SF10",0,4}, - {0,72,4,0,4,"CORR_SIG_NOISE_RATIO_SF11",0,4}, - {0,73,0,0,4,"CORR_SIG_NOISE_RATIO_SF12",0,4}, - {0,74,0,0,4,"CORR_NUM_SAME_PEAK",0,4}, - {0,74,4,0,3,"CORR_MAC_GAIN",0,5}, - {0,75,0,0,12,"ADJUST_MODEM_START_OFFSET_RDX8",0,0}, - {0,77,0,0,12,"ADJUST_MODEM_START_OFFSET_RDX4",0,0}, - {0,79,0,0,12,"ADJUST_MODEM_START_OFFSET_SF12_RDX4",0,4092}, - {0,81,0,0,8,"DBG_CORR_SELECT_SF",0,7}, - {0,82,0,0,8,"DBG_CORR_SELECT_CHANNEL",0,0}, - {0,83,0,0,8,"DBG_DETECT_CPT",1,0}, - {0,84,0,0,8,"DBG_SYMB_CPT",1,0}, - {0,85,0,0,1,"CHIRP_INVERT_RX",0,1}, - {0,85,1,0,1,"DC_NOTCH_EN",0,0}, - {0,86,0,0,1,"IMPLICIT_CRC_EN",0,0}, - {0,86,1,0,3,"IMPLICIT_CODING_RATE",0,0}, - {0,87,0,0,8,"IMPLICIT_PAYLOAD_LENGHT",0,0}, - {0,88,0,0,8,"FREQ_TO_TIME_INVERT",0,29}, - {0,89,0,0,6,"FREQ_TO_TIME_DRIFT",0,9}, - {0,90,0,0,2,"PAYLOAD_FINE_TIMING_GAIN",0,2}, - {0,90,2,0,2,"PREAMBLE_FINE_TIMING_GAIN",0,1}, - {0,90,4,0,2,"TRACKING_INTEGRAL",0,0}, - {0,91,0,0,4,"FRAME_SYNCH_PEAK1_POS",0,1}, - {0,91,4,0,4,"FRAME_SYNCH_PEAK2_POS",0,2}, - {0,92,0,0,16,"PREAMBLE_SYMB1_NB",0,10}, - {0,94,0,0,1,"FRAME_SYNCH_GAIN",0,1}, - {0,94,1,0,1,"SYNCH_DETECT_TH",0,1}, - {0,95,0,0,4,"LLR_SCALE",0,8}, - {0,95,4,0,2,"SNR_AVG_CST",0,2}, - {0,96,0,0,7,"PPM_OFFSET",0,0}, - {0,97,0,0,8,"MAX_PAYLOAD_LEN",0,255}, - {0,98,0,0,1,"ONLY_CRC_EN",0,1}, - {0,99,0,0,8,"ZERO_PAD",0,0}, - {0,100,0,0,4,"DEC_GAIN_OFFSET",0,8}, - {0,101,0,0,1,"FORCE_HOST_REG_CTRL",0,1}, - {0,101,1,0,1,"FORCE_HOST_RADIO_CTRL",0,1}, - {0,101,2,0,1,"FORCE_HOST_FE_CTRL",0,1}, - {0,101,3,0,1,"FORCE_DEC_FILTER_GAIN",0,1}, - {0,102,0,0,1,"MCU_RST_0",0,1}, - {0,102,1,0,1,"MCU_RST_1",0,1}, - {0,102,2,0,1,"MCU_SELECT_MUX_0",0,0}, - {0,102,3,0,1,"MCU_SELECT_MUX_1",0,0}, - {0,102,4,0,1,"MCU_CORRUPTION_DETECTED_0",1,0}, - {0,102,5,0,1,"MCU_CORRUPTION_DETECTED_1",1,0}, - {0,103,0,0,8,"CHANN_SELECT_RSSI",0,1}, - {0,104,0,0,8,"RSSI_BB_DEFAULT_VALUE",0,32}, - {0,105,0,0,8,"RSSI_DEC_DEFAULT_VALUE",0,100}, - {0,106,0,0,8,"RSSI_CHANN_DEFAULT_VALUE",0,100}, - {0,107,0,0,5,"RSSI_BB_FILTER_ALPHA",0,7}, - {0,108,0,0,5,"RSSI_DEC_FILTER_ALPHA",0,5}, - {0,109,0,0,5,"RSSI_CHANN_FILTER_ALPHA",0,8}, - {0,110,0,0,6,"IQ_MISMATCH_A_AMP_COEFF",0,0}, - {0,111,0,0,6,"IQ_MISMATCH_A_PHI_COEFF",0,0}, - {0,112,0,0,6,"IQ_MISMATCH_B_AMP_COEFF",0,0}, - {0,112,6,0,1,"IQ_MISMATCH_B_SEL_I",0,0}, - {0,113,0,0,6,"IQ_MISMATCH_B_PHI_COEFF",0,0}, - {1,29,0,0,1,"TX_TRIG_IMMEDIATE",0,0}, - {1,29,1,0,1,"TX_TRIG_DELAYED",0,0}, - {1,29,2,0,1,"TX_TRIG_GPS",0,0}, - {1,30,0,0,16,"TX_START_DELAY",0,0}, - {1,32,0,0,4,"TX_FRAME_SYNCH_PEAK1_POS",0,1}, - {1,32,4,0,4,"TX_FRAME_SYNCH_PEAK2_POS",0,2}, - {1,33,0,0,16,"TX_PREAMBLE_SYMB1_NB",0,10}, - {1,35,0,0,8,"TX_OFFSET_I",0,0}, - {1,36,0,0,8,"TX_OFFSET_Q",0,0}, - {1,37,0,0,1,"TX_MODE",0,0}, - {1,37,1,0,4,"TX_ZERO_PAD",0,0}, - {1,37,5,0,1,"TX_PPM_OFFSET",0,0}, - {1,37,6,0,1,"TX_CHIRP_INVERT",0,0}, - {1,37,7,0,1,"TX_CONT_CHIRP",0,0}, - {1,38,0,0,2,"TX_GAIN",0,0}, - {1,38,2,0,3,"TX_CHIRP_LOW_PASS",0,0}, - {1,38,5,0,2,"TX_FCC_WIDEBAND",0,0}, - {1,38,7,0,1,"TX_SWAP_IQ",0,0}, - {1,39,0,0,1,"MBWSSF_IMPLICIT_HEADER",0,0}, - {1,39,1,0,1,"MBWSSF_IMPLICIT_CRC_EN",0,0}, - {1,39,2,0,3,"MBWSSF_IMPLICIT_CODING_RATE",0,0}, - {1,40,0,0,8,"MBWSSF_IMPLICIT_PAYLOAD_LENGHT",0,0}, - {1,41,0,0,1,"MBWSSF_AGC_FREEZE_ON_DETECT",0,1}, - {1,42,0,0,4,"MBWSSF_FRAME_SYNCH_PEAK1_POS",0,1}, - {1,42,4,0,4,"MBWSSF_FRAME_SYNCH_PEAK2_POS",0,2}, - {1,43,0,0,16,"MBWSSF_PREAMBLE_SYMB1_NB",0,10}, - {1,45,0,0,1,"MBWSSF_FRAME_SYNCH_GAIN",0,1}, - {1,45,1,0,1,"MBWSSF_SYNCH_DETECT_TH",0,1}, - {1,46,0,0,8,"MBWSSF_DETECT_MIN_SINGLE_PEAK",0,10}, - {1,47,0,0,3,"MBWSSF_DETECT_TRIG_SAME_PEAK_NB",0,3}, - {1,48,0,0,8,"MBWSSF_FREQ_TO_TIME_INVERT",0,29}, - {1,49,0,0,6,"MBWSSF_FREQ_TO_TIME_DRIFT",0,36}, - {1,50,0,0,12,"MBWSSF_PPM_CORRECTION",0,0}, - {1,52,0,0,2,"MBWSSF_PAYLOAD_FINE_TIMING_GAIN",0,2}, - {1,52,2,0,2,"MBWSSF_PREAMBLE_FINE_TIMING_GAIN",0,1}, - {1,52,4,0,2,"MBWSSF_TRACKING_INTEGRAL",0,0}, - {1,53,0,0,8,"MBWSSF_ZERO_PAD",0,0}, - {1,54,0,0,2,"MBWSSF_MODEM_BW",0,0}, - {1,54,2,0,1,"MBWSSF_RADIO_SELECT",0,0}, - {1,54,3,0,1,"MBWSSF_RX_CHIRP_INVERT",0,1}, - {1,55,0,0,4,"MBWSSF_LLR_SCALE",0,8}, - {1,55,4,0,2,"MBWSSF_SNR_AVG_CST",0,3}, - {1,55,6,0,1,"MBWSSF_PPM_OFFSET",0,0}, - {1,56,0,0,4,"MBWSSF_RATE_SF",0,7}, - {1,56,4,0,1,"MBWSSF_ONLY_CRC_EN",0,1}, - {1,57,0,0,8,"MBWSSF_MAX_PAYLOAD_LEN",0,255}, - {2,29,0,0,8,"SPI_RADIO_A__DATA",0,0}, - {2,30,0,0,8,"SPI_RADIO_A__DATA_READBACK",1,0}, - {2,31,0,0,14,"SPI_RADIO_A__ADDR",0,0}, - {2,33,0,0,1,"SPI_RADIO_A__CS",0,0}, - {2,34,0,0,8,"SPI_RADIO_B__DATA",0,0}, - {2,35,0,0,8,"SPI_RADIO_B__DATA_READBACK",1,0}, - {2,36,0,0,14,"SPI_RADIO_B__ADDR",0,0}, - {2,38,0,0,1,"SPI_RADIO_B__CS",0,0}, - {2,39,0,0,1,"RADIO_A_EN",0,0}, - {2,39,1,0,1,"RADIO_B_EN",0,0}, - {2,39,2,0,1,"RADIO_RST",0,1}, - {2,39,3,0,1,"LNA_A_EN",0,0}, - {2,39,4,0,1,"PA_A_EN",0,0}, - {2,39,5,0,1,"LNA_B_EN",0,0}, - {2,39,6,0,1,"PA_B_EN",0,0}, - {2,40,0,0,2,"PA_A_GAIN",0,0}, - {2,40,2,0,2,"PA_B_GAIN",0,0}, - {2,41,0,0,4,"LNA_A_CTRL_LUT",0,2}, - {2,41,4,0,4,"PA_A_CTRL_LUT",0,4}, - {2,42,0,0,4,"LNA_B_CTRL_LUT",0,2}, - {2,42,4,0,4,"PA_B_CTRL_LUT",0,4}, - {2,43,0,0,5,"CAPTURE_SOURCE",0,0}, - {2,43,5,0,1,"CAPTURE_START",0,0}, - {2,43,6,0,1,"CAPTURE_FORCE_TRIGGER",0,0}, - {2,43,7,0,1,"CAPTURE_WRAP",0,0}, - {2,44,0,0,16,"CAPTURE_PERIOD",0,0}, - {2,46,0,0,3,"LED_REG",0,3}, - {2,47,0,0,8,"MODEM_STATUS",1,0}, - {2,48,0,0,8,"VALID_HEADER_COUNTER_0",1,0}, - {2,49,0,0,8,"VALID_HEADER_COUNTER_1",1,0}, - {2,50,0,0,8,"VALID_PACKET_COUNTER_0",1,0}, - {2,51,0,0,8,"VALID_PACKET_COUNTER_1",1,0}, - {2,52,0,0,8,"VALID_HEADER_COUNTER_MBWSSF",1,0}, - {2,53,0,0,8,"VALID_HEADER_COUNTER_FSK",1,0}, - {2,54,0,0,8,"VALID_PACKET_COUNTER_MBWSSF",1,0}, - {2,55,0,0,8,"VALID_PACKET_COUNTER_FSK",1,0}, - {2,56,0,0,8,"CHANN_RSSI",1,0}, - {2,57,0,0,8,"BB_RSSI",1,0}, - {2,58,0,0,8,"DEC_RSSI",1,0}, - {2,59,0,0,8,"DBG_MCU_DATA",1,0}, - {2,60,0,0,8,"DBG_ARB_MCU_RAM_DATA",1,0}, - {2,61,0,0,8,"DBG_AGC_MCU_RAM_DATA",1,0}, - {2,62,0,0,16,"NEXT_PACKET_CNT",1,0}, - {2,64,0,0,16,"ADDR_CAPTURE_COUNT",1,0}, - {2,66,0,0,32,"TIMESTAMP",1,0}, - {2,70,0,0,4,"DBG_CHANN0_GAIN",1,0}, - {2,70,4,0,4,"DBG_CHANN1_GAIN",1,0}, - {2,71,0,0,4,"DBG_CHANN2_GAIN",1,0}, - {2,71,4,0,4,"DBG_CHANN3_GAIN",1,0}, - {2,72,0,0,4,"DBG_CHANN4_GAIN",1,0}, - {2,72,4,0,4,"DBG_CHANN5_GAIN",1,0}, - {2,73,0,0,4,"DBG_CHANN6_GAIN",1,0}, - {2,73,4,0,4,"DBG_CHANN7_GAIN",1,0}, - {2,74,0,0,4,"DBG_DEC_FILT_GAIN",1,0}, - {2,75,0,0,3,"SPI_DATA_FIFO_PTR",1,0}, - {2,75,3,0,3,"PACKET_DATA_FIFO_PTR",1,0}, - {2,76,0,0,8,"DBG_ARB_MCU_RAM_ADDR",0,0}, - {2,77,0,0,8,"DBG_AGC_MCU_RAM_ADDR",0,0}, - {2,78,0,0,1,"SPI_MASTER_CHIP_SELECT_POLARITY",0,0}, - {2,78,1,0,1,"SPI_MASTER_CPOL",0,0}, - {2,78,2,0,1,"SPI_MASTER_CPHA",0,0}, - {2,79,0,0,1,"SIG_GEN_ANALYSER_MUX_SEL",0,0}, - {2,80,0,0,1,"SIG_GEN_EN",0,0}, - {2,80,1,0,1,"SIG_ANALYSER_EN",0,0}, - {2,80,2,0,2,"SIG_ANALYSER_AVG_LEN",0,0}, - {2,80,4,0,3,"SIG_ANALYSER_PRECISION",0,0}, - {2,80,7,0,1,"SIG_ANALYSER_VALID_OUT",1,0}, - {2,81,0,0,8,"SIG_GEN_FREQ",0,0}, - {2,82,0,0,8,"SIG_ANALYSER_FREQ",0,0}, - {2,83,0,0,8,"SIG_ANALYSER_I_OUT",1,0}, - {2,84,0,0,8,"SIG_ANALYSER_Q_OUT",1,0}, - {2,85,0,0,1,"GPS_EN",0,0}, - {2,85,1,0,1,"GPS_POL",0,1} + {-1,0,0,0,2,"PAGE_REG",0,0}, + {-1,0,7,0,1,"SOFT_RESET",0,0}, + {-1,1,0,0,8,"VERSION",1,100}, + {-1,2,0,0,16,"RX_DATA_BUF_ADDR",0,0}, + {-1,4,0,0,8,"RX_DATA_BUF_DATA",1,0}, + {-1,5,0,0,8,"TX_DATA_BUF_ADDR",0,0}, + {-1,6,0,0,8,"TX_DATA_BUF_DATA",0,0}, + {-1,7,0,0,8,"CAPTURE_RAM_ADDR",0,0}, + {-1,8,0,0,8,"CAPTURE_RAM_DATA",1,0}, + {-1,9,0,0,8,"MCU_PROM_ADDR",0,0}, + {-1,10,0,0,8,"MCU_PROM_DATA",0,0}, + {-1,11,0,0,8,"RX_PACKET_DATA_FIFO_NUM_STORED",0,0}, + {-1,12,0,0,16,"RX_PACKET_DATA_FIFO_ADDR_POINTER",1,0}, + {-1,14,0,0,8,"RX_PACKET_DATA_FIFO_STATUS",1,0}, + {-1,15,0,0,8,"RX_PACKET_DATA_FIFO_PAYLOAD_SIZE",1,0}, + {-1,16,0,0,1,"MBWSSF_MODEM_ENABLE",0,0}, + {-1,16,1,0,1,"CONCENTRATOR_MODEM_ENABLE",0,0}, + {-1,16,2,0,1,"FSK_MODEM_ENABLE",0,0}, + {-1,17,0,0,1,"CLK32M_EN",0,0}, + {-1,17,1,0,1,"CLKHS_EN",0,0}, + {-1,18,0,0,1,"START_BIST0",0,0}, + {-1,18,1,0,1,"START_BIST1",0,0}, + {-1,18,2,0,1,"CLEAR_BIST0",0,0}, + {-1,18,3,0,1,"CLEAR_BIST1",0,0}, + {-1,19,0,0,1,"BIST0_FINISHED",1,0}, + {-1,19,1,0,1,"BIST1_FINISHED",1,0}, + {-1,20,0,0,1,"MCU_AGC_PROG_RAM_BIST_STATUS",1,0}, + {-1,20,1,0,1,"MCU_ARB_PROG_RAM_BIST_STATUS",1,0}, + {-1,20,2,0,1,"CAPTURE_RAM_BIST_STATUS",1,0}, + {-1,20,3,0,1,"CHAN_FIR_RAM0_BIST_STATUS",1,0}, + {-1,20,4,0,1,"CHAN_FIR_RAM1_BIST_STATUS",1,0}, + {-1,21,0,0,1,"CORR0_RAM_BIST_STATUS",1,0}, + {-1,21,1,0,1,"CORR1_RAM_BIST_STATUS",1,0}, + {-1,21,2,0,1,"CORR2_RAM_BIST_STATUS",1,0}, + {-1,21,3,0,1,"CORR3_RAM_BIST_STATUS",1,0}, + {-1,21,4,0,1,"CORR4_RAM_BIST_STATUS",1,0}, + {-1,21,5,0,1,"CORR5_RAM_BIST_STATUS",1,0}, + {-1,21,6,0,1,"CORR6_RAM_BIST_STATUS",1,0}, + {-1,21,7,0,1,"CORR7_RAM_BIST_STATUS",1,0}, + {-1,22,0,0,1,"MODEM0_RAM0_BIST_STATUS",1,0}, + {-1,22,1,0,1,"MODEM1_RAM0_BIST_STATUS",1,0}, + {-1,22,2,0,1,"MODEM2_RAM0_BIST_STATUS",1,0}, + {-1,22,3,0,1,"MODEM3_RAM0_BIST_STATUS",1,0}, + {-1,22,4,0,1,"MODEM4_RAM0_BIST_STATUS",1,0}, + {-1,22,5,0,1,"MODEM5_RAM0_BIST_STATUS",1,0}, + {-1,22,6,0,1,"MODEM6_RAM0_BIST_STATUS",1,0}, + {-1,22,7,0,1,"MODEM7_RAM0_BIST_STATUS",1,0}, + {-1,23,0,0,1,"MODEM0_RAM1_BIST_STATUS",1,0}, + {-1,23,1,0,1,"MODEM1_RAM1_BIST_STATUS",1,0}, + {-1,23,2,0,1,"MODEM2_RAM1_BIST_STATUS",1,0}, + {-1,23,3,0,1,"MODEM3_RAM1_BIST_STATUS",1,0}, + {-1,23,4,0,1,"MODEM4_RAM1_BIST_STATUS",1,0}, + {-1,23,5,0,1,"MODEM5_RAM1_BIST_STATUS",1,0}, + {-1,23,6,0,1,"MODEM6_RAM1_BIST_STATUS",1,0}, + {-1,23,7,0,1,"MODEM7_RAM1_BIST_STATUS",1,0}, + {-1,24,0,0,1,"MODEM0_RAM2_BIST_STATUS",1,0}, + {-1,24,1,0,1,"MODEM1_RAM2_BIST_STATUS",1,0}, + {-1,24,2,0,1,"MODEM2_RAM2_BIST_STATUS",1,0}, + {-1,24,3,0,1,"MODEM3_RAM2_BIST_STATUS",1,0}, + {-1,24,4,0,1,"MODEM4_RAM2_BIST_STATUS",1,0}, + {-1,24,5,0,1,"MODEM5_RAM2_BIST_STATUS",1,0}, + {-1,24,6,0,1,"MODEM6_RAM2_BIST_STATUS",1,0}, + {-1,24,7,0,1,"MODEM7_RAM2_BIST_STATUS",1,0}, + {-1,25,0,0,1,"MODEM_MBWSSF_RAM0_BIST_STATUS",1,0}, + {-1,25,1,0,1,"MODEM_MBWSSF_RAM1_BIST_STATUS",1,0}, + {-1,25,2,0,1,"MODEM_MBWSSF_RAM2_BIST_STATUS",1,0}, + {-1,26,0,0,1,"MCU_AGC_DATA_RAM_BIST0_STATUS",1,0}, + {-1,26,1,0,1,"MCU_AGC_DATA_RAM_BIST1_STATUS",1,0}, + {-1,26,2,0,1,"MCU_ARB_DATA_RAM_BIST0_STATUS",1,0}, + {-1,26,3,0,1,"MCU_ARB_DATA_RAM_BIST1_STATUS",1,0}, + {-1,26,4,0,1,"TX_TOP_RAM_BIST0_STATUS",1,0}, + {-1,26,5,0,1,"TX_TOP_RAM_BIST1_STATUS",1,0}, + {-1,26,6,0,1,"DATA_MNGT_RAM_BIST0_STATUS",1,0}, + {-1,26,7,0,1,"DATA_MNGT_RAM_BIST1_STATUS",1,0}, + {-1,27,0,0,8,"GPIO_SELECT",0,0}, + {-1,28,0,0,8,"GPIO_MUX",0,0}, + {-1,127,0,0,1,"EMERGENCY_FORCE_HOST_CTRL",0,0}, + {0,29,0,0,1,"RX_INVERT_IQ",0,0}, + {0,29,1,0,1,"MODEM_INVERT_IQ",0,1}, + {0,29,2,0,1,"MBWSSF_MODEM_INVERT_IQ",0,0}, + {0,29,3,0,1,"RX_EDGE_SELECT",0,0}, + {0,29,4,0,1,"MISC_RADIO_EN",0,0}, + {0,30,0,0,4,"FILTER_GAIN",0,7}, + {0,31,0,0,8,"RADIO_SELECT",0,240}, + {0,32,0,1,13,"IF_FREQ_0",0,-384}, + {0,34,0,1,13,"IF_FREQ_1",0,-128}, + {0,36,0,1,13,"IF_FREQ_2",0,128}, + {0,38,0,1,13,"IF_FREQ_3",0,384}, + {0,40,0,1,13,"IF_FREQ_4",0,-384}, + {0,42,0,1,13,"IF_FREQ_5",0,-128}, + {0,44,0,1,13,"IF_FREQ_6",0,128}, + {0,46,0,1,13,"IF_FREQ_7",0,384}, + {0,48,0,1,13,"IF_FREQ_8",0,0}, + {0,50,0,1,13,"IF_FREQ_9",0,0}, + {0,60,0,0,1,"CHANN_OVERRIDE_AGC_GAIN",0,0}, + {0,60,1,0,4,"CHANN_AGC_GAIN",0,7}, + {0,61,0,0,7,"CORR0_DETECT_EN",0,0}, + {0,62,0,0,7,"CORR1_DETECT_EN",0,0}, + {0,63,0,0,7,"CORR2_DETECT_EN",0,0}, + {0,64,0,0,7,"CORR3_DETECT_EN",0,0}, + {0,65,0,0,7,"CORR4_DETECT_EN",0,0}, + {0,66,0,0,7,"CORR5_DETECT_EN",0,0}, + {0,67,0,0,7,"CORR6_DETECT_EN",0,0}, + {0,68,0,0,7,"CORR7_DETECT_EN",0,0}, + {0,69,0,0,1,"CORR_SAME_PEAKS_OPTION_SF6",0,0}, + {0,69,1,0,1,"CORR_SAME_PEAKS_OPTION_SF7",0,1}, + {0,69,2,0,1,"CORR_SAME_PEAKS_OPTION_SF8",0,1}, + {0,69,3,0,1,"CORR_SAME_PEAKS_OPTION_SF9",0,1}, + {0,69,4,0,1,"CORR_SAME_PEAKS_OPTION_SF10",0,1}, + {0,69,5,0,1,"CORR_SAME_PEAKS_OPTION_SF11",0,1}, + {0,69,6,0,1,"CORR_SAME_PEAKS_OPTION_SF12",0,1}, + {0,70,0,0,4,"CORR_SIG_NOISE_RATIO_SF6",0,4}, + {0,70,4,0,4,"CORR_SIG_NOISE_RATIO_SF7",0,4}, + {0,71,0,0,4,"CORR_SIG_NOISE_RATIO_SF8",0,4}, + {0,71,4,0,4,"CORR_SIG_NOISE_RATIO_SF9",0,4}, + {0,72,0,0,4,"CORR_SIG_NOISE_RATIO_SF10",0,4}, + {0,72,4,0,4,"CORR_SIG_NOISE_RATIO_SF11",0,4}, + {0,73,0,0,4,"CORR_SIG_NOISE_RATIO_SF12",0,4}, + {0,74,0,0,4,"CORR_NUM_SAME_PEAK",0,4}, + {0,74,4,0,3,"CORR_MAC_GAIN",0,5}, + {0,75,0,0,12,"ADJUST_MODEM_START_OFFSET_RDX8",0,0}, + {0,77,0,0,12,"ADJUST_MODEM_START_OFFSET_RDX4",0,0}, + {0,79,0,0,12,"ADJUST_MODEM_START_OFFSET_SF12_RDX4",0,4092}, + {0,81,0,0,8,"DBG_CORR_SELECT_SF",0,7}, + {0,82,0,0,8,"DBG_CORR_SELECT_CHANNEL",0,0}, + {0,83,0,0,8,"DBG_DETECT_CPT",1,0}, + {0,84,0,0,8,"DBG_SYMB_CPT",1,0}, + {0,85,0,0,1,"CHIRP_INVERT_RX",0,1}, + {0,85,1,0,1,"DC_NOTCH_EN",0,0}, + {0,86,0,0,1,"IMPLICIT_CRC_EN",0,0}, + {0,86,1,0,3,"IMPLICIT_CODING_RATE",0,0}, + {0,87,0,0,8,"IMPLICIT_PAYLOAD_LENGHT",0,0}, + {0,88,0,0,8,"FREQ_TO_TIME_INVERT",0,29}, + {0,89,0,0,6,"FREQ_TO_TIME_DRIFT",0,9}, + {0,90,0,0,2,"PAYLOAD_FINE_TIMING_GAIN",0,2}, + {0,90,2,0,2,"PREAMBLE_FINE_TIMING_GAIN",0,1}, + {0,90,4,0,2,"TRACKING_INTEGRAL",0,0}, + {0,91,0,0,4,"FRAME_SYNCH_PEAK1_POS",0,1}, + {0,91,4,0,4,"FRAME_SYNCH_PEAK2_POS",0,2}, + {0,92,0,0,16,"PREAMBLE_SYMB1_NB",0,10}, + {0,94,0,0,1,"FRAME_SYNCH_GAIN",0,1}, + {0,94,1,0,1,"SYNCH_DETECT_TH",0,1}, + {0,95,0,0,4,"LLR_SCALE",0,8}, + {0,95,4,0,2,"SNR_AVG_CST",0,2}, + {0,96,0,0,7,"PPM_OFFSET",0,0}, + {0,97,0,0,8,"MAX_PAYLOAD_LEN",0,255}, + {0,98,0,0,1,"ONLY_CRC_EN",0,1}, + {0,99,0,0,8,"ZERO_PAD",0,0}, + {0,100,0,0,4,"DEC_GAIN_OFFSET",0,8}, + {0,101,0,0,1,"FORCE_HOST_REG_CTRL",0,1}, + {0,101,1,0,1,"FORCE_HOST_RADIO_CTRL",0,1}, + {0,101,2,0,1,"FORCE_HOST_FE_CTRL",0,1}, + {0,101,3,0,1,"FORCE_DEC_FILTER_GAIN",0,1}, + {0,102,0,0,1,"MCU_RST_0",0,1}, + {0,102,1,0,1,"MCU_RST_1",0,1}, + {0,102,2,0,1,"MCU_SELECT_MUX_0",0,0}, + {0,102,3,0,1,"MCU_SELECT_MUX_1",0,0}, + {0,102,4,0,1,"MCU_CORRUPTION_DETECTED_0",1,0}, + {0,102,5,0,1,"MCU_CORRUPTION_DETECTED_1",1,0}, + {0,103,0,0,8,"CHANN_SELECT_RSSI",0,1}, + {0,104,0,0,8,"RSSI_BB_DEFAULT_VALUE",0,32}, + {0,105,0,0,8,"RSSI_DEC_DEFAULT_VALUE",0,100}, + {0,106,0,0,8,"RSSI_CHANN_DEFAULT_VALUE",0,100}, + {0,107,0,0,5,"RSSI_BB_FILTER_ALPHA",0,7}, + {0,108,0,0,5,"RSSI_DEC_FILTER_ALPHA",0,5}, + {0,109,0,0,5,"RSSI_CHANN_FILTER_ALPHA",0,8}, + {0,110,0,0,6,"IQ_MISMATCH_A_AMP_COEFF",0,0}, + {0,111,0,0,6,"IQ_MISMATCH_A_PHI_COEFF",0,0}, + {0,112,0,0,6,"IQ_MISMATCH_B_AMP_COEFF",0,0}, + {0,112,6,0,1,"IQ_MISMATCH_B_SEL_I",0,0}, + {0,113,0,0,6,"IQ_MISMATCH_B_PHI_COEFF",0,0}, + {1,29,0,0,1,"TX_TRIG_IMMEDIATE",0,0}, + {1,29,1,0,1,"TX_TRIG_DELAYED",0,0}, + {1,29,2,0,1,"TX_TRIG_GPS",0,0}, + {1,30,0,0,16,"TX_START_DELAY",0,0}, + {1,32,0,0,4,"TX_FRAME_SYNCH_PEAK1_POS",0,1}, + {1,32,4,0,4,"TX_FRAME_SYNCH_PEAK2_POS",0,2}, + {1,33,0,0,16,"TX_PREAMBLE_SYMB1_NB",0,10}, + {1,35,0,0,8,"TX_OFFSET_I",0,0}, + {1,36,0,0,8,"TX_OFFSET_Q",0,0}, + {1,37,0,0,1,"TX_MODE",0,0}, + {1,37,1,0,4,"TX_ZERO_PAD",0,0}, + {1,37,5,0,1,"TX_PPM_OFFSET",0,0}, + {1,37,6,0,1,"TX_CHIRP_INVERT",0,0}, + {1,37,7,0,1,"TX_CONT_CHIRP",0,0}, + {1,38,0,0,2,"TX_GAIN",0,0}, + {1,38,2,0,3,"TX_CHIRP_LOW_PASS",0,0}, + {1,38,5,0,2,"TX_FCC_WIDEBAND",0,0}, + {1,38,7,0,1,"TX_SWAP_IQ",0,0}, + {1,39,0,0,1,"MBWSSF_IMPLICIT_HEADER",0,0}, + {1,39,1,0,1,"MBWSSF_IMPLICIT_CRC_EN",0,0}, + {1,39,2,0,3,"MBWSSF_IMPLICIT_CODING_RATE",0,0}, + {1,40,0,0,8,"MBWSSF_IMPLICIT_PAYLOAD_LENGHT",0,0}, + {1,41,0,0,1,"MBWSSF_AGC_FREEZE_ON_DETECT",0,1}, + {1,42,0,0,4,"MBWSSF_FRAME_SYNCH_PEAK1_POS",0,1}, + {1,42,4,0,4,"MBWSSF_FRAME_SYNCH_PEAK2_POS",0,2}, + {1,43,0,0,16,"MBWSSF_PREAMBLE_SYMB1_NB",0,10}, + {1,45,0,0,1,"MBWSSF_FRAME_SYNCH_GAIN",0,1}, + {1,45,1,0,1,"MBWSSF_SYNCH_DETECT_TH",0,1}, + {1,46,0,0,8,"MBWSSF_DETECT_MIN_SINGLE_PEAK",0,10}, + {1,47,0,0,3,"MBWSSF_DETECT_TRIG_SAME_PEAK_NB",0,3}, + {1,48,0,0,8,"MBWSSF_FREQ_TO_TIME_INVERT",0,29}, + {1,49,0,0,6,"MBWSSF_FREQ_TO_TIME_DRIFT",0,36}, + {1,50,0,0,12,"MBWSSF_PPM_CORRECTION",0,0}, + {1,52,0,0,2,"MBWSSF_PAYLOAD_FINE_TIMING_GAIN",0,2}, + {1,52,2,0,2,"MBWSSF_PREAMBLE_FINE_TIMING_GAIN",0,1}, + {1,52,4,0,2,"MBWSSF_TRACKING_INTEGRAL",0,0}, + {1,53,0,0,8,"MBWSSF_ZERO_PAD",0,0}, + {1,54,0,0,2,"MBWSSF_MODEM_BW",0,0}, + {1,54,2,0,1,"MBWSSF_RADIO_SELECT",0,0}, + {1,54,3,0,1,"MBWSSF_RX_CHIRP_INVERT",0,1}, + {1,55,0,0,4,"MBWSSF_LLR_SCALE",0,8}, + {1,55,4,0,2,"MBWSSF_SNR_AVG_CST",0,3}, + {1,55,6,0,1,"MBWSSF_PPM_OFFSET",0,0}, + {1,56,0,0,4,"MBWSSF_RATE_SF",0,7}, + {1,56,4,0,1,"MBWSSF_ONLY_CRC_EN",0,1}, + {1,57,0,0,8,"MBWSSF_MAX_PAYLOAD_LEN",0,255}, + {2,29,0,0,8,"SPI_RADIO_A__DATA",0,0}, + {2,30,0,0,8,"SPI_RADIO_A__DATA_READBACK",1,0}, + {2,31,0,0,14,"SPI_RADIO_A__ADDR",0,0}, + {2,33,0,0,1,"SPI_RADIO_A__CS",0,0}, + {2,34,0,0,8,"SPI_RADIO_B__DATA",0,0}, + {2,35,0,0,8,"SPI_RADIO_B__DATA_READBACK",1,0}, + {2,36,0,0,14,"SPI_RADIO_B__ADDR",0,0}, + {2,38,0,0,1,"SPI_RADIO_B__CS",0,0}, + {2,39,0,0,1,"RADIO_A_EN",0,0}, + {2,39,1,0,1,"RADIO_B_EN",0,0}, + {2,39,2,0,1,"RADIO_RST",0,1}, + {2,39,3,0,1,"LNA_A_EN",0,0}, + {2,39,4,0,1,"PA_A_EN",0,0}, + {2,39,5,0,1,"LNA_B_EN",0,0}, + {2,39,6,0,1,"PA_B_EN",0,0}, + {2,40,0,0,2,"PA_A_GAIN",0,0}, + {2,40,2,0,2,"PA_B_GAIN",0,0}, + {2,41,0,0,4,"LNA_A_CTRL_LUT",0,2}, + {2,41,4,0,4,"PA_A_CTRL_LUT",0,4}, + {2,42,0,0,4,"LNA_B_CTRL_LUT",0,2}, + {2,42,4,0,4,"PA_B_CTRL_LUT",0,4}, + {2,43,0,0,5,"CAPTURE_SOURCE",0,0}, + {2,43,5,0,1,"CAPTURE_START",0,0}, + {2,43,6,0,1,"CAPTURE_FORCE_TRIGGER",0,0}, + {2,43,7,0,1,"CAPTURE_WRAP",0,0}, + {2,44,0,0,16,"CAPTURE_PERIOD",0,0}, + {2,46,0,0,3,"LED_REG",0,3}, + {2,47,0,0,8,"MODEM_STATUS",1,0}, + {2,48,0,0,8,"VALID_HEADER_COUNTER_0",1,0}, + {2,49,0,0,8,"VALID_HEADER_COUNTER_1",1,0}, + {2,50,0,0,8,"VALID_PACKET_COUNTER_0",1,0}, + {2,51,0,0,8,"VALID_PACKET_COUNTER_1",1,0}, + {2,52,0,0,8,"VALID_HEADER_COUNTER_MBWSSF",1,0}, + {2,53,0,0,8,"VALID_HEADER_COUNTER_FSK",1,0}, + {2,54,0,0,8,"VALID_PACKET_COUNTER_MBWSSF",1,0}, + {2,55,0,0,8,"VALID_PACKET_COUNTER_FSK",1,0}, + {2,56,0,0,8,"CHANN_RSSI",1,0}, + {2,57,0,0,8,"BB_RSSI",1,0}, + {2,58,0,0,8,"DEC_RSSI",1,0}, + {2,59,0,0,8,"DBG_MCU_DATA",1,0}, + {2,60,0,0,8,"DBG_ARB_MCU_RAM_DATA",1,0}, + {2,61,0,0,8,"DBG_AGC_MCU_RAM_DATA",1,0}, + {2,62,0,0,16,"NEXT_PACKET_CNT",1,0}, + {2,64,0,0,16,"ADDR_CAPTURE_COUNT",1,0}, + {2,66,0,0,32,"TIMESTAMP",1,0}, + {2,70,0,0,4,"DBG_CHANN0_GAIN",1,0}, + {2,70,4,0,4,"DBG_CHANN1_GAIN",1,0}, + {2,71,0,0,4,"DBG_CHANN2_GAIN",1,0}, + {2,71,4,0,4,"DBG_CHANN3_GAIN",1,0}, + {2,72,0,0,4,"DBG_CHANN4_GAIN",1,0}, + {2,72,4,0,4,"DBG_CHANN5_GAIN",1,0}, + {2,73,0,0,4,"DBG_CHANN6_GAIN",1,0}, + {2,73,4,0,4,"DBG_CHANN7_GAIN",1,0}, + {2,74,0,0,4,"DBG_DEC_FILT_GAIN",1,0}, + {2,75,0,0,3,"SPI_DATA_FIFO_PTR",1,0}, + {2,75,3,0,3,"PACKET_DATA_FIFO_PTR",1,0}, + {2,76,0,0,8,"DBG_ARB_MCU_RAM_ADDR",0,0}, + {2,77,0,0,8,"DBG_AGC_MCU_RAM_ADDR",0,0}, + {2,78,0,0,1,"SPI_MASTER_CHIP_SELECT_POLARITY",0,0}, + {2,78,1,0,1,"SPI_MASTER_CPOL",0,0}, + {2,78,2,0,1,"SPI_MASTER_CPHA",0,0}, + {2,79,0,0,1,"SIG_GEN_ANALYSER_MUX_SEL",0,0}, + {2,80,0,0,1,"SIG_GEN_EN",0,0}, + {2,80,1,0,1,"SIG_ANALYSER_EN",0,0}, + {2,80,2,0,2,"SIG_ANALYSER_AVG_LEN",0,0}, + {2,80,4,0,3,"SIG_ANALYSER_PRECISION",0,0}, + {2,80,7,0,1,"SIG_ANALYSER_VALID_OUT",1,0}, + {2,81,0,0,8,"SIG_GEN_FREQ",0,0}, + {2,82,0,0,8,"SIG_ANALYSER_FREQ",0,0}, + {2,83,0,0,8,"SIG_ANALYSER_I_OUT",1,0}, + {2,84,0,0,8,"SIG_ANALYSER_Q_OUT",1,0}, + {2,85,0,0,1,"GPS_EN",0,0}, + {2,85,1,0,1,"GPS_POL",0,1} }; /* -------------------------------------------------------------------------- */ @@ -367,9 +367,9 @@ static int lgw_regpage = -1; /*! keep the value of the register page selected */ /* --- PRIVATE FUNCTIONS ---------------------------------------------------- */ int page_switch(uint8_t target) { - lgw_regpage = PAGE_MASK & target; - lgw_spi_w(lgw_spidesc, PAGE_ADDR, (uint8_t)lgw_regpage); - return LGW_REG_SUCCESS; + lgw_regpage = PAGE_MASK & target; + lgw_spi_w(lgw_spidesc, PAGE_ADDR, (uint8_t)lgw_regpage); + return LGW_REG_SUCCESS; } /* -------------------------------------------------------------------------- */ @@ -377,347 +377,347 @@ int page_switch(uint8_t target) { /* Gateway connect */ int lgw_connect(void) { - int spi_stat = LGW_SPI_SUCCESS; - uint8_t u = 0; - - if (lgw_spidesc >= 0) { - DEBUG_MSG("WARNING: gateway was already connected\n"); - lgw_spi_close(lgw_spidesc); - } - /* open the SPI link */ - spi_stat = lgw_spi_open(&lgw_spidesc); - 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); - if (spi_stat != LGW_SPI_SUCCESS) { - DEBUG_MSG("ERROR WRITING PAGE REGISTER\n"); - return LGW_REG_ERROR; - } else { - lgw_regpage = 0; - } - /* checking the version register */ - spi_stat = lgw_spi_r(lgw_spidesc, loregs[LGW_VERSION].addr, &u); - if (spi_stat != LGW_SPI_SUCCESS) { - DEBUG_MSG("ERROR READING VERSION REGISTER\n"); - return LGW_REG_ERROR; - } else if (u == 0) { - DEBUG_MSG("ERROR: GATEWAY SEEMS DISCONNECTED\n"); - return LGW_REG_ERROR; - } else if (u != loregs[LGW_VERSION].dflt) { - DEBUG_MSG("ERROR: MISMATCH BETWEEN EXPECTED REG VERSION AND READ REG VERSION\n"); - return LGW_REG_ERROR; - } - DEBUG_MSG("Note: success connecting the gateway\n"); - return LGW_REG_SUCCESS; + int spi_stat = LGW_SPI_SUCCESS; + uint8_t u = 0; + + if (lgw_spidesc >= 0) { + DEBUG_MSG("WARNING: gateway was already connected\n"); + lgw_spi_close(lgw_spidesc); + } + /* open the SPI link */ + spi_stat = lgw_spi_open(&lgw_spidesc); + 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); + if (spi_stat != LGW_SPI_SUCCESS) { + DEBUG_MSG("ERROR WRITING PAGE REGISTER\n"); + return LGW_REG_ERROR; + } else { + lgw_regpage = 0; + } + /* checking the version register */ + spi_stat = lgw_spi_r(lgw_spidesc, loregs[LGW_VERSION].addr, &u); + if (spi_stat != LGW_SPI_SUCCESS) { + DEBUG_MSG("ERROR READING VERSION REGISTER\n"); + return LGW_REG_ERROR; + } else if (u == 0) { + DEBUG_MSG("ERROR: GATEWAY SEEMS DISCONNECTED\n"); + return LGW_REG_ERROR; + } else if (u != loregs[LGW_VERSION].dflt) { + DEBUG_MSG("ERROR: MISMATCH BETWEEN EXPECTED REG VERSION AND READ REG VERSION\n"); + return LGW_REG_ERROR; + } + DEBUG_MSG("Note: success connecting the gateway\n"); + return LGW_REG_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Gateway disconnect */ int lgw_disconnect(void) { - if (lgw_spidesc >= 0) { - lgw_spi_close(lgw_spidesc); - lgw_spidesc = -1; - 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; - } + if (lgw_spidesc >= 0) { + lgw_spi_close(lgw_spidesc); + lgw_spidesc = -1; + 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; + } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* soft-reset function */ int lgw_soft_reset(void) { - int32_t read_value; - /* check if SPI is initialised */ - if ((lgw_spidesc < 0) || (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_regpage = 0; /* reset the paging static variable */ - return LGW_REG_SUCCESS; + int32_t read_value; + /* check if SPI is initialised */ + if ((lgw_spidesc < 0) || (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_regpage = 0; /* reset the paging static variable */ + return LGW_REG_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* register verification */ int lgw_reg_check(FILE *f) { - struct lgw_reg_s r; - int32_t read_value; - char ok_msg[] = "+++MATCH+++"; - char notok_msg[] = "###MISMATCH###"; - char *ptr; - int i; - - /* check if SPI is initialised */ - if ((lgw_spidesc < 0) || (lgw_regpage < 0)) { - DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n"); - fprintf(f, "ERROR: GATEWAY UNCONNECTED\n"); - return LGW_REG_ERROR; - } - - fprintf(f, "Start of register verification\n"); - for (i=0; i<LGW_TOTALREGS; ++i) { - r = loregs[i]; - lgw_reg_r(i, &read_value); - ptr = (read_value == r.dflt) ? ok_msg : notok_msg; - if (r.sign == true) - fprintf(f, "%s reg: %s read: %d (%x) default: %d (%x)\n", ptr, r.name, read_value, read_value, r.dflt, r.dflt); - else - fprintf(f, "%s reg: %s read: %u (%x) default: %u (%x)\n", ptr, r.name, read_value, read_value, r.dflt, r.dflt); - } - fprintf(f, "End of register verification\n"); - - return LGW_REG_SUCCESS; + struct lgw_reg_s r; + int32_t read_value; + char ok_msg[] = "+++MATCH+++"; + char notok_msg[] = "###MISMATCH###"; + char *ptr; + int i; + + /* check if SPI is initialised */ + if ((lgw_spidesc < 0) || (lgw_regpage < 0)) { + DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n"); + fprintf(f, "ERROR: GATEWAY UNCONNECTED\n"); + return LGW_REG_ERROR; + } + + fprintf(f, "Start of register verification\n"); + for (i=0; i<LGW_TOTALREGS; ++i) { + r = loregs[i]; + lgw_reg_r(i, &read_value); + ptr = (read_value == r.dflt) ? ok_msg : notok_msg; + if (r.sign == true) + fprintf(f, "%s reg: %s read: %d (%x) default: %d (%x)\n", ptr, r.name, read_value, read_value, r.dflt, r.dflt); + else + fprintf(f, "%s reg: %s read: %u (%x) default: %u (%x)\n", ptr, r.name, read_value, read_value, r.dflt, r.dflt); + } + fprintf(f, "End of register verification\n"); + + return LGW_REG_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Write to a register addressed by name */ int lgw_reg_w(uint16_t register_id, int32_t reg_value) { - int spi_stat = LGW_SPI_SUCCESS; - struct lgw_reg_s r; - uint8_t buf[4] = "\x00\x00\x00\x00"; - int i, size_byte; - - /* check input parameters */ - if (register_id >= LGW_TOTALREGS) { - DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n"); - return LGW_REG_ERROR; - } - - /* check if SPI is initialised */ - if ((lgw_spidesc < 0) || (lgw_regpage < 0)) { - DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n"); - return LGW_REG_ERROR; - } - - /* intercept direct access to PAGE_REG & SOFT_RESET */ - if (register_id == LGW_PAGE_REG) { - page_switch(reg_value); - return LGW_REG_SUCCESS; - } else if (register_id == LGW_SOFT_RESET) { - /* only reset if lsb is 1 */ - if (reg_value%2 != 0) - lgw_soft_reset(); - return LGW_REG_SUCCESS; - } - - /* get register struct from the struct array */ - r = loregs[register_id]; - - /* reject write to read-only registers */ - if (r.rdon == 1){ - DEBUG_MSG("ERROR: TRYING TO WRITE A READ-ONLY REGISTER\n"); - return LGW_REG_ERROR; - } - - /* select proper register page if needed */ - if ((r.page != -1) && (r.page != lgw_regpage)) { - spi_stat += page_switch(r.page); - } - - if ((r.leng == 8) && (r.offs == 0)) { - /* direct write */ - spi_stat += lgw_spi_w(lgw_spidesc, 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]); - 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]); - } 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 */ - for (i=0; i<size_byte; ++i) { - /* big endian register file for a file on N bytes - Least significant byte is stored in buf[0], most one in buf[N-1] */ - 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 */ - } else { - /* register spanning multiple memory bytes but with an offset */ - DEBUG_MSG("ERROR: REGISTER SIZE AND OFFSET ARE NOT SUPPORTED\n"); - return LGW_REG_ERROR; - } - - if (spi_stat != LGW_SPI_SUCCESS) { - DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER WRITE\n"); - return LGW_REG_ERROR; - } else { - return LGW_REG_SUCCESS; - } + int spi_stat = LGW_SPI_SUCCESS; + struct lgw_reg_s r; + uint8_t buf[4] = "\x00\x00\x00\x00"; + int i, size_byte; + + /* check input parameters */ + if (register_id >= LGW_TOTALREGS) { + DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n"); + return LGW_REG_ERROR; + } + + /* check if SPI is initialised */ + if ((lgw_spidesc < 0) || (lgw_regpage < 0)) { + DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n"); + return LGW_REG_ERROR; + } + + /* intercept direct access to PAGE_REG & SOFT_RESET */ + if (register_id == LGW_PAGE_REG) { + page_switch(reg_value); + return LGW_REG_SUCCESS; + } else if (register_id == LGW_SOFT_RESET) { + /* only reset if lsb is 1 */ + if ((reg_value & 0x01) != 0) + lgw_soft_reset(); + return LGW_REG_SUCCESS; + } + + /* get register struct from the struct array */ + r = loregs[register_id]; + + /* reject write to read-only registers */ + if (r.rdon == 1){ + DEBUG_MSG("ERROR: TRYING TO WRITE A READ-ONLY REGISTER\n"); + return LGW_REG_ERROR; + } + + /* select proper register page if needed */ + if ((r.page != -1) && (r.page != lgw_regpage)) { + spi_stat += page_switch(r.page); + } + + if ((r.leng == 8) && (r.offs == 0)) { + /* direct write */ + spi_stat += lgw_spi_w(lgw_spidesc, 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]); + 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]); + } 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 */ + for (i=0; i<size_byte; ++i) { + /* big endian register file for a file on N bytes + Least significant byte is stored in buf[0], most one in buf[N-1] */ + 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 */ + } else { + /* register spanning multiple memory bytes but with an offset */ + DEBUG_MSG("ERROR: REGISTER SIZE AND OFFSET ARE NOT SUPPORTED\n"); + return LGW_REG_ERROR; + } + + if (spi_stat != LGW_SPI_SUCCESS) { + DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER WRITE\n"); + return LGW_REG_ERROR; + } else { + return LGW_REG_SUCCESS; + } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Read to a register addressed by name */ int lgw_reg_r(uint16_t register_id, int32_t *reg_value) { - int spi_stat = LGW_SPI_SUCCESS; - struct lgw_reg_s r; - uint8_t bufu[4] = "\x00\x00\x00\x00"; - int8_t *bufs = bufu; - int i, size_byte; - uint32_t u = 0; - - /* check input parameters */ - CHECK_NULL(reg_value); - if (register_id >= LGW_TOTALREGS) { - DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n"); - return LGW_REG_ERROR; - } - - /* check if SPI is initialised */ - if ((lgw_spidesc < 0) || (lgw_regpage < 0)) { - DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n"); - return LGW_REG_ERROR; - } - - /* get register struct from the struct array */ - r = loregs[register_id]; - - /* select proper register page if needed */ - if ((r.page != -1) && (r.page != lgw_regpage)) { - spi_stat += page_switch(r.page); - } - - 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]); - 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 */ - *reg_value = (int32_t)bufs[2]; /* signed pointer -> 32b sign extension */ - } else { - bufu[2] = bufu[1] >> (8 - r.leng); /* right align the data, no sign extension */ - *reg_value = (int32_t)bufu[2]; /* unsigned pointer -> no sign extension */ - } - } 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); - 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 */ - } - if (r.sign == true) { - u = u << (32 - r.leng); /* left-align the data */ - *reg_value = (int32_t)u >> (32 - r.leng); /* right-align the data with sign extension */ - } else { - *reg_value = (int32_t)u; /* unsigned value -> return 'as is' */ - } - } else { - /* register spanning multiple memory bytes but with an offset */ - DEBUG_MSG("ERROR: REGISTER SIZE AND OFFSET ARE NOT SUPPORTED\n"); - return LGW_REG_ERROR; - } - - if (spi_stat != LGW_SPI_SUCCESS) { - DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER WRITE\n"); - return LGW_REG_ERROR; - } else { - return LGW_REG_SUCCESS; - } + int spi_stat = LGW_SPI_SUCCESS; + struct lgw_reg_s r; + uint8_t bufu[4] = "\x00\x00\x00\x00"; + int8_t *bufs = bufu; + int i, size_byte; + uint32_t u = 0; + + /* check input parameters */ + CHECK_NULL(reg_value); + if (register_id >= LGW_TOTALREGS) { + DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n"); + return LGW_REG_ERROR; + } + + /* check if SPI is initialised */ + if ((lgw_spidesc < 0) || (lgw_regpage < 0)) { + DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n"); + return LGW_REG_ERROR; + } + + /* get register struct from the struct array */ + r = loregs[register_id]; + + /* select proper register page if needed */ + if ((r.page != -1) && (r.page != lgw_regpage)) { + spi_stat += page_switch(r.page); + } + + 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]); + 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) */ + *reg_value = (int32_t)bufs[2]; /* signed pointer -> 32b sign extension */ + } else { + bufu[2] = bufu[1] >> (8 - r.leng); /* right align the data, no sign extension */ + *reg_value = (int32_t)bufu[2]; /* unsigned pointer -> no sign extension */ + } + } 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); + 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 */ + } + if (r.sign == true) { + u = u << (32 - r.leng); /* left-align the data */ + *reg_value = (int32_t)u >> (32 - r.leng); /* right-align the data with sign extension (ARITHMETIC right shift) */ + } else { + *reg_value = (int32_t)u; /* unsigned value -> return 'as is' */ + } + } else { + /* register spanning multiple memory bytes but with an offset */ + DEBUG_MSG("ERROR: REGISTER SIZE AND OFFSET ARE NOT SUPPORTED\n"); + return LGW_REG_ERROR; + } + + if (spi_stat != LGW_SPI_SUCCESS) { + DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER WRITE\n"); + return LGW_REG_ERROR; + } else { + return LGW_REG_SUCCESS; + } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Point to a register by name and do a burst write */ int lgw_reg_wb(uint16_t register_id, uint8_t *data, uint16_t size) { - int spi_stat; - struct lgw_reg_s r; - - /* check input parameters */ - CHECK_NULL(data); - if (size == 0) { - DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); - return LGW_REG_ERROR; - } - if (register_id >= LGW_TOTALREGS) { - DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n"); - return LGW_REG_ERROR; - } - - /* check if SPI is initialised */ - if ((lgw_spidesc < 0) || (lgw_regpage < 0)) { - DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n"); - return LGW_REG_ERROR; - } - - /* get register struct from the struct array */ - r = loregs[register_id]; - - /* reject write to read-only registers */ - if (r.rdon == 1){ - DEBUG_MSG("ERROR: TRYING TO BURST WRITE A READ-ONLY REGISTER\n"); - return LGW_REG_ERROR; - } - - /* select proper register page if needed */ - if ((r.page != -1) && (r.page != lgw_regpage)) { - spi_stat += page_switch(r.page); - } - - /* do the burst write */ - spi_stat = lgw_spi_wb(lgw_spidesc, r.addr, data, size); - - if (spi_stat != LGW_SPI_SUCCESS) { - DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST WRITE\n"); - return LGW_REG_ERROR; - } else { - return LGW_REG_SUCCESS; - } + int spi_stat; + struct lgw_reg_s r; + + /* check input parameters */ + CHECK_NULL(data); + if (size == 0) { + DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); + return LGW_REG_ERROR; + } + if (register_id >= LGW_TOTALREGS) { + DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n"); + return LGW_REG_ERROR; + } + + /* check if SPI is initialised */ + if ((lgw_spidesc < 0) || (lgw_regpage < 0)) { + DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n"); + return LGW_REG_ERROR; + } + + /* get register struct from the struct array */ + r = loregs[register_id]; + + /* reject write to read-only registers */ + if (r.rdon == 1){ + DEBUG_MSG("ERROR: TRYING TO BURST WRITE A READ-ONLY REGISTER\n"); + return LGW_REG_ERROR; + } + + /* select proper register page if needed */ + if ((r.page != -1) && (r.page != lgw_regpage)) { + spi_stat += page_switch(r.page); + } + + /* do the burst write */ + spi_stat = lgw_spi_wb(lgw_spidesc, r.addr, data, size); + + if (spi_stat != LGW_SPI_SUCCESS) { + DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST WRITE\n"); + return LGW_REG_ERROR; + } else { + return LGW_REG_SUCCESS; + } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Point to a register by name and do a burst read */ int lgw_reg_rb(uint16_t register_id, uint8_t *data, uint16_t size) { - int spi_stat; - struct lgw_reg_s r; - - /* check input parameters */ - CHECK_NULL(data); - if (size == 0) { - DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); - return LGW_REG_ERROR; - } - if (register_id >= LGW_TOTALREGS) { - DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n"); - return LGW_REG_ERROR; - } - - /* check if SPI is initialised */ - if ((lgw_spidesc < 0) || (lgw_regpage < 0)) { - DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n"); - return LGW_REG_ERROR; - } - - /* get register struct from the struct array */ - r = loregs[register_id]; - - /* select proper register page if needed */ - if ((r.page != -1) && (r.page != lgw_regpage)) { - spi_stat += page_switch(r.page); - } - - /* do the burst read */ - spi_stat = lgw_spi_rb(lgw_spidesc, r.addr, data, size); - - if (spi_stat != LGW_SPI_SUCCESS) { - DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST READ\n"); - return LGW_REG_ERROR; - } else { - return LGW_REG_SUCCESS; - } + int spi_stat; + struct lgw_reg_s r; + + /* check input parameters */ + CHECK_NULL(data); + if (size == 0) { + DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); + return LGW_REG_ERROR; + } + if (register_id >= LGW_TOTALREGS) { + DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n"); + return LGW_REG_ERROR; + } + + /* check if SPI is initialised */ + if ((lgw_spidesc < 0) || (lgw_regpage < 0)) { + DEBUG_MSG("ERROR: GATEWAY UNCONNECTED\n"); + return LGW_REG_ERROR; + } + + /* get register struct from the struct array */ + r = loregs[register_id]; + + /* select proper register page if needed */ + if ((r.page != -1) && (r.page != lgw_regpage)) { + spi_stat += page_switch(r.page); + } + + /* do the burst read */ + spi_stat = lgw_spi_rb(lgw_spidesc, r.addr, data, size); + + if (spi_stat != LGW_SPI_SUCCESS) { + DEBUG_MSG("ERROR: SPI ERROR DURING REGISTER BURST READ\n"); + return LGW_REG_ERROR; + } else { + return LGW_REG_SUCCESS; + } } /* --- EOF ------------------------------------------------------------------ */ diff --git a/loragw_hal/src/loragw_spi.c b/loragw_hal/src/loragw_spi.c index 4c0b4f9..fa8581c 100644 --- a/loragw_hal/src/loragw_spi.c +++ b/loragw_hal/src/loragw_spi.c @@ -1,28 +1,28 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - Host specific functions to address the LoRa™ gateway registers through a - SPI interface. - Single-byte read/write and burst read/write. - Does not handle pagination. - Could be used with multiple SPI ports in parallel (explicit file descriptor) + Host specific functions to address the LoRa™ gateway registers through a + SPI interface. + Single-byte read/write and burst read/write. + Does not handle pagination. + Could be used with multiple SPI ports in parallel (explicit file descriptor) */ /* -------------------------------------------------------------------------- */ /* --- DEPENDANCIES --------------------------------------------------------- */ -#include <stdint.h> /* C99 types */ -#include <stdio.h> /* printf fprintf */ -#include <unistd.h> /* lseek, close */ -#include <fcntl.h> /* open */ -#include <string.h> /* memset */ +#include <stdint.h> /* C99 types */ +#include <stdio.h> /* printf fprintf */ +#include <unistd.h> /* lseek, close */ +#include <fcntl.h> /* open */ +#include <string.h> /* memset */ #include <sys/ioctl.h> #include <linux/spi/spidev.h> @@ -34,260 +34,260 @@ Description: #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #ifdef DEBUG - #define DEBUG_MSG(str) fprintf(stderr, str) - #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) - #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_SPI_ERROR;} + #define DEBUG_MSG(str) fprintf(stderr, str) + #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) + #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_SPI_ERROR;} #else - #define DEBUG_MSG(str) - #define DEBUG_PRINTF(fmt, args...) - #define CHECK_NULL(a) if(a==NULL){return LGW_SPI_ERROR;} + #define DEBUG_MSG(str) + #define DEBUG_PRINTF(fmt, args...) + #define CHECK_NULL(a) if(a==NULL){return LGW_SPI_ERROR;} #endif /* -------------------------------------------------------------------------- */ /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ -#define READ_ACCESS 0x00 -#define WRITE_ACCESS 0x80 -#define SPI_SPEED 8000000 -#define SPI_DEV_PATH "/dev/spidev0.0" +#define READ_ACCESS 0x00 +#define WRITE_ACCESS 0x80 +#define SPI_SPEED 8000000 +#define SPI_DEV_PATH "/dev/spidev0.0" /* -------------------------------------------------------------------------- */ /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ /* SPI initialization and configuration */ int lgw_spi_open(int *spi_device) { - int i,j,k,l; - - CHECK_NULL(spi_device); - - /* open SPI device */ - i = open(SPI_DEV_PATH, O_RDWR); - if (i < 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)) { - DEBUG_MSG("ERROR: SPI PORT FAIL TO SET IN MODE 0\n"); - close(i); - 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)) { - DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MAX SPEED\n"); - close(i); - 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)) { - DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MSB FIRST\n"); - close(i); - 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)) { - DEBUG_MSG("ERROR: SPI PORT FAIL TO SET 8 BITS-PER-WORD\n"); - close(i); - return LGW_SPI_ERROR; - } - DEBUG_MSG("Note: SPI port opened and configured ok\n"); - *spi_device = i; - return LGW_SPI_SUCCESS; + int i,j,k,l; + + CHECK_NULL(spi_device); + + /* open SPI device */ + i = open(SPI_DEV_PATH, O_RDWR); + if (i < 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)) { + DEBUG_MSG("ERROR: SPI PORT FAIL TO SET IN MODE 0\n"); + close(i); + 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)) { + DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MAX SPEED\n"); + close(i); + 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)) { + DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MSB FIRST\n"); + close(i); + 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)) { + DEBUG_MSG("ERROR: SPI PORT FAIL TO SET 8 BITS-PER-WORD\n"); + close(i); + return LGW_SPI_ERROR; + } + DEBUG_MSG("Note: SPI port opened and configured ok\n"); + *spi_device = i; + return LGW_SPI_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* SPI release */ int lgw_spi_close(int spi_device) { - int i; - - i = close(spi_device); - if (i < 0) { - DEBUG_MSG("ERROR: SPI PORT FAILED TO CLOSE\n"); - return LGW_SPI_ERROR; - } else { - DEBUG_MSG("Note: SPI port closed\n"); - return LGW_SPI_SUCCESS; - } + int i; + + i = close(spi_device); + if (i < 0) { + DEBUG_MSG("ERROR: SPI PORT FAILED TO CLOSE\n"); + return LGW_SPI_ERROR; + } else { + DEBUG_MSG("Note: SPI port closed\n"); + return LGW_SPI_SUCCESS; + } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Simple write */ int lgw_spi_w(int spi_device, uint8_t address, uint8_t data) { - uint8_t outbuf[2]; - struct spi_ioc_transfer k; - int i; - - outbuf[0] = WRITE_ACCESS | (address & 0x7F); - outbuf[1] = data; - - memset(&k, 0, sizeof(k)); /* clear k */ - k.tx_buf = (unsigned long) outbuf; - k.len = ARRAY_SIZE(outbuf); - k.speed_hz = SPI_SPEED; - k.cs_change = 1; - k.bits_per_word = 8; - - i = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); - - if (i != 2) { - DEBUG_MSG("ERROR: SPI WRITE FAILURE\n"); - return LGW_SPI_ERROR; - } else { - DEBUG_MSG("Note: SPI write success\n"); - return LGW_SPI_SUCCESS; - } + uint8_t outbuf[2]; + struct spi_ioc_transfer k; + int i; + + outbuf[0] = WRITE_ACCESS | (address & 0x7F); + outbuf[1] = data; + + memset(&k, 0, sizeof(k)); /* clear k */ + k.tx_buf = (unsigned long) outbuf; + k.len = ARRAY_SIZE(outbuf); + k.speed_hz = SPI_SPEED; + k.cs_change = 1; + k.bits_per_word = 8; + + i = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); + + if (i != 2) { + DEBUG_MSG("ERROR: SPI WRITE FAILURE\n"); + return LGW_SPI_ERROR; + } else { + DEBUG_MSG("Note: SPI write success\n"); + return LGW_SPI_SUCCESS; + } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Simple read */ int lgw_spi_r(int spi_device, uint8_t address, uint8_t *data) { - uint8_t outbuf[2]; - uint8_t inbuf[ARRAY_SIZE(outbuf)]; - struct spi_ioc_transfer k; - int i; - - CHECK_NULL(data); - - outbuf[0] = READ_ACCESS | (address & 0x7F); - outbuf[1] = 0x00; - - 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.cs_change = 1; - - i = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); - - if (i != 2) { - DEBUG_MSG("ERROR: SPI READ FAILURE\n"); - return LGW_SPI_ERROR; - } else { - DEBUG_MSG("Note: SPI read success\n"); - *data = inbuf[1]; - return LGW_SPI_SUCCESS; - } + uint8_t outbuf[2]; + uint8_t inbuf[ARRAY_SIZE(outbuf)]; + struct spi_ioc_transfer k; + int i; + + CHECK_NULL(data); + + outbuf[0] = READ_ACCESS | (address & 0x7F); + outbuf[1] = 0x00; + + 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.cs_change = 1; + + i = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); + + if (i != 2) { + DEBUG_MSG("ERROR: SPI READ FAILURE\n"); + return LGW_SPI_ERROR; + } else { + DEBUG_MSG("Note: SPI read success\n"); + *data = inbuf[1]; + return LGW_SPI_SUCCESS; + } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Burst (multiple-byte) write */ int lgw_spi_wb(int spi_device, uint8_t address, uint8_t *data, uint16_t size) { - uint8_t command; - struct spi_ioc_transfer k[2]; - int byte_to_trans; - int chunk_size; - int offset = 0; - int byte_transfered = 0; - - /* check input parameters */ - 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 */ - command = WRITE_ACCESS | (address & 0x7F); - 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; - 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; - } - - if (byte_transfered != size) { - DEBUG_MSG("ERROR: SPI BURST WRITE FAILURE\n"); - return LGW_SPI_ERROR; - } else { - DEBUG_MSG("Note: SPI burst write success\n"); - return LGW_SPI_SUCCESS; - } + uint8_t command; + struct spi_ioc_transfer k[2]; + int byte_to_trans; + int chunk_size; + int offset = 0; + int byte_transfered = 0; + + /* check input parameters */ + 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 */ + command = WRITE_ACCESS | (address & 0x7F); + 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; + 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; + } + + if (byte_transfered != size) { + DEBUG_MSG("ERROR: SPI BURST WRITE FAILURE\n"); + return LGW_SPI_ERROR; + } else { + DEBUG_MSG("Note: SPI burst write success\n"); + return LGW_SPI_SUCCESS; + } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Burst (multiple-byte) read */ int lgw_spi_rb(int spi_device, uint8_t address, uint8_t *data, uint16_t size) { - uint8_t command; - struct spi_ioc_transfer k[2]; - int byte_to_trans; - int chunk_size; - int offset = 0; - int byte_transfered = 0; - - /* check input parameters */ - 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 */ - command = READ_ACCESS | (address & 0x7F); - 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; - 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; - } - - if (byte_transfered != size) { - DEBUG_MSG("ERROR: SPI BURST READ FAILURE\n"); - return LGW_SPI_ERROR; - } else { - DEBUG_MSG("Note: SPI burst read success\n"); - return LGW_SPI_SUCCESS; - } + uint8_t command; + struct spi_ioc_transfer k[2]; + int byte_to_trans; + int chunk_size; + int offset = 0; + int byte_transfered = 0; + + /* check input parameters */ + 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 */ + command = READ_ACCESS | (address & 0x7F); + 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; + 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; + } + + if (byte_transfered != size) { + DEBUG_MSG("ERROR: SPI BURST READ FAILURE\n"); + return LGW_SPI_ERROR; + } else { + DEBUG_MSG("Note: SPI burst read success\n"); + return LGW_SPI_SUCCESS; + } } /* --- EOF ------------------------------------------------------------------ */ diff --git a/loragw_hal/test/test_loragw_hal.c b/loragw_hal/test/test_loragw_hal.c index dbe6831..fc7964c 100644 --- a/loragw_hal/test/test_loragw_hal.c +++ b/loragw_hal/test/test_loragw_hal.c @@ -1,13 +1,13 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - Minimum test program for the loragw_hal 'library' + Minimum test program for the loragw_hal 'library' */ @@ -16,17 +16,17 @@ Description: /* fix an issue between POSIX and C99 */ #if __STDC_VERSION__ >= 199901L - #define _XOPEN_SOURCE 600 + #define _XOPEN_SOURCE 600 #else - #define _XOPEN_SOURCE 500 + #define _XOPEN_SOURCE 500 #endif -#include <stdint.h> /* C99 types */ -#include <stdlib.h> /* malloc & free */ -#include <stdbool.h> /* bool type */ -#include <stdio.h> /* printf */ -#include <string.h> /* memset */ -#include <signal.h> /* sigaction */ +#include <stdint.h> /* C99 types */ +#include <stdlib.h> /* malloc & free */ +#include <stdbool.h> /* bool type */ +#include <stdio.h> /* printf */ +#include <string.h> /* memset */ +#include <signal.h> /* sigaction */ #include "loragw_hal.h" #include "loragw_aux.h" @@ -51,11 +51,11 @@ static void sig_handler(int sigio); /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ static void sig_handler(int sigio) { - if (sigio == SIGQUIT) { - quit_sig = 1;; - } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { - exit_sig = 1; - } + if (sigio == SIGQUIT) { + quit_sig = 1;; + } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { + exit_sig = 1; + } } /* -------------------------------------------------------------------------- */ @@ -63,188 +63,189 @@ static void sig_handler(int sigio) { int main(int argc, char **argv) { - struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ - - struct lgw_conf_rxrf_s rfconf; - struct lgw_conf_rxif_s ifconf; - - struct lgw_pkt_rx_s rxpkt[4]; /* array containing up to 4 inbound packets metadata */ - struct lgw_pkt_tx_s txpkt; /* configuration and metadata for an outbound packet */ - uint8_t txbuf[256]; /* buffer for the TX payload */ - struct lgw_pkt_rx_s *p; /* pointer on a RX packet */ - - int i, j; - int nb_pkt; - uint8_t x; - - int tx_cnt = 0; - int tx_path = 0; - struct lgw_pkt_tx_s txs; - - /* configure signal handling */ - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - sigact.sa_handler = sig_handler; - sigaction(SIGQUIT, &sigact, NULL); - sigaction(SIGINT, &sigact, NULL); - sigaction(SIGTERM, &sigact, NULL); - - /* beginning of Lora gateway-specific code */ - printf("Beginning of test for loragw_hal.c\n"); - - /* set configuration for RF chains */ - memset(&rfconf, 0, sizeof(rfconf)); - - rfconf.enable = true; - rfconf.freq_hz = 866187500; - lgw_rxrf_setconf(0, rfconf); /* radio A */ - - rfconf.enable = true; - rfconf.freq_hz = 866437500; - lgw_rxrf_setconf(1, rfconf); /* radio B */ - - /* set configuration for Lora multi-SF channels (bandwidth cannot be set) */ - memset(&ifconf, 0, sizeof(ifconf)); - - ifconf.enable = true; - ifconf.rf_chain = 0; - ifconf.freq_hz = -187500; - ifconf.bandwidth = BW_125KHZ; - ifconf.datarate = DR_LORA_MULTI; - lgw_rxif_setconf(0, ifconf); /* chain 0: 1st radio, bleeper channel 1, all SF */ - - ifconf.enable = true; - ifconf.rf_chain = 0; - ifconf.freq_hz = -62500; - ifconf.bandwidth = BW_125KHZ; - ifconf.datarate = DR_LORA_SF8 | DR_LORA_SF10; - lgw_rxif_setconf(1, ifconf); /* chain 1: 1st radio, bleeper channel 2, SF8 & SF10 only */ - - ifconf.enable = false; - ifconf.rf_chain = 0; - ifconf.freq_hz = 0; - ifconf.bandwidth = 0; - ifconf.datarate = 0; - lgw_rxif_setconf(2, ifconf); /* chain 2: 1st radio, disabled */ - - ifconf.enable = true; - ifconf.rf_chain = 1; - ifconf.freq_hz = -187500; - ifconf.bandwidth = BW_125KHZ; - ifconf.datarate = DR_LORA_MULTI; - lgw_rxif_setconf(3, ifconf); /* chain 3: 2nd radio, bleeper channel 3, all SF */ - - /* set configuration for Lora 'stand alone' channel */ - ifconf.enable = true; - ifconf.rf_chain = 0; - ifconf.freq_hz = 187500; - ifconf.bandwidth = BW_125KHZ; - ifconf.datarate = DR_LORA_SF10; - lgw_rxif_setconf(8, ifconf); /* chain 8: bleeper channel 4, SF10 only */ - - /* set configuration for TX packet */ - memset(&txs, 0, sizeof(txs)); - txs.freq_hz = 866250000; - txs.tx_mode = IMMEDIATE; - txs.modulation = MOD_LORA; - txs.bandwidth = BW_250KHZ; - txs.datarate = DR_LORA_SF10; - txs.coderate = CR_LORA_4_5; - txs.payload = "TX.TEST.LORA.GATEWAY"; - txs.size = 20; - - /* connect, configure and start the Lora gateway */ - lgw_start(); - - while ((quit_sig != 1) && (exit_sig != 1)) { - /* fetch N packets */ - nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt); - - if (nb_pkt == 0) { - wait_ms(300); - } else { - printf("\nLora gateway, %d packets received:\n\n", nb_pkt); - /* display received packets */ - for(i=0; i < nb_pkt; ++i) { - p = &rxpkt[i]; - printf("---\nPkt #%d >>", i+1); - if (p->status == STAT_CRC_OK) { - printf(" if_chain:%2d", p->if_chain); - printf(" tstamp:%010u", p->count_us); - printf(" size:%3u", p->size); - switch (p-> modulation) { - case MOD_LORA: printf(" Lora"); break; - case MOD_FSK: printf(" FSK"); break; - case MOD_GFSK: printf(" GFSK"); break; - default: printf(" modulation?"); - } - switch (p->datarate) { - case DR_LORA_SF7: printf(" SF7"); break; - case DR_LORA_SF8: printf(" SF8"); break; - case DR_LORA_SF9: printf(" SF9"); break; - case DR_LORA_SF10: printf(" SF10"); break; - case DR_LORA_SF11: printf(" SF11"); break; - case DR_LORA_SF12: printf(" SF12"); break; - default: printf(" datarate?"); - } - switch (p->coderate) { - case CR_LORA_4_5: printf(" CR1(4/5)"); break; - case CR_LORA_4_6: printf(" CR2(2/3)"); break; - case CR_LORA_4_7: printf(" CR3(4/7)"); break; - case CR_LORA_4_8: printf(" CR4(1/2)"); break; - default: printf(" coderate?"); - } - printf("\n"); - printf(" RSSI:%+6.1f SNR:%+5.1f (min:%+5.1f, max:%+5.1f) payload:\n", p->rssi, p->snr, p->snr_min, p->snr_max); - for (j = 0; j < p->size; ++j) { - printf(" %02X", p->payload[j]); - } - printf(" #\n"); - } else if (p->status == STAT_CRC_BAD) { - printf(" if_chain:%2d", p->if_chain); - printf(" tstamp:%010u", p->count_us); - printf(" size:%3u\n", p->size); - printf(" CRC error, damaged packet\n\n"); - } else if (p->status == STAT_NO_CRC){ - printf(" if_chain:%2d", p->if_chain); - printf(" tstamp:%010u", p->count_us); - printf(" size:%3u\n", p->size); - printf(" no CRC\n\n"); - } else { - printf(" if_chain:%2d", p->if_chain); - printf(" tstamp:%010u", p->count_us); - printf(" size:%3u\n", p->size); - printf(" invalid status ?!?\n\n"); - } - } - - /* free the memory used for RX payload(s) */ - for(i=0; i < nb_pkt; ++i) { - free(rxpkt[i].payload); - } - } - - /* send a packet every X loop */ - if (tx_cnt >= 5) { - tx_cnt = 0; - - txs.rf_chain = tx_path; /* alternate between path A and B */ - i = lgw_send(txs); - printf("Packet sent, rf path %d, status %d\n", txs.rf_chain, i); - - tx_path = (tx_path+1) % 2; - } else { - ++tx_cnt; - } - } - - if (exit_sig == 1) { - /* clean up before leaving */ - lgw_stop(); - } - - printf("End of test for loragw_hal.c\n"); - return 0; + struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ + + struct lgw_conf_rxrf_s rfconf; + struct lgw_conf_rxif_s ifconf; + + struct lgw_pkt_rx_s rxpkt[4]; /* array containing up to 4 inbound packets metadata */ + struct lgw_pkt_tx_s txpkt; /* configuration and metadata for an outbound packet */ + uint8_t txbuf[256]; /* buffer for the TX payload */ + struct lgw_pkt_rx_s *p; /* pointer on a RX packet */ + + int i, j; + int nb_pkt; + uint8_t x; + + int tx_cnt = 0; + int tx_path = 0; + struct lgw_pkt_tx_s txs; + + /* configure signal handling */ + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigact.sa_handler = sig_handler; + sigaction(SIGQUIT, &sigact, NULL); + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + + /* beginning of Lora gateway-specific code */ + printf("Beginning of test for loragw_hal.c\n"); + + /* set configuration for RF chains */ + memset(&rfconf, 0, sizeof(rfconf)); + + rfconf.enable = true; + rfconf.freq_hz = 866187500; + lgw_rxrf_setconf(0, rfconf); /* radio A */ + + rfconf.enable = true; + rfconf.freq_hz = 866437500; + lgw_rxrf_setconf(1, rfconf); /* radio B */ + + /* set configuration for Lora multi-SF channels (bandwidth cannot be set) */ + memset(&ifconf, 0, sizeof(ifconf)); + + ifconf.enable = true; + ifconf.rf_chain = 0; + ifconf.freq_hz = -187500; + ifconf.bandwidth = BW_125KHZ; + ifconf.datarate = DR_LORA_MULTI; + lgw_rxif_setconf(0, ifconf); /* chain 0: 1st radio, bleeper channel 1, all SF */ + + ifconf.enable = true; + ifconf.rf_chain = 0; + ifconf.freq_hz = -62500; + ifconf.bandwidth = BW_125KHZ; + ifconf.datarate = DR_LORA_SF8 | DR_LORA_SF10; + lgw_rxif_setconf(1, ifconf); /* chain 1: 1st radio, bleeper channel 2, SF8 & SF10 only */ + + ifconf.enable = false; + ifconf.rf_chain = 0; + ifconf.freq_hz = 0; + ifconf.bandwidth = 0; + ifconf.datarate = 0; + lgw_rxif_setconf(2, ifconf); /* chain 2: 1st radio, disabled */ + + ifconf.enable = true; + ifconf.rf_chain = 1; + ifconf.freq_hz = -187500; + ifconf.bandwidth = BW_125KHZ; + ifconf.datarate = DR_LORA_MULTI; + lgw_rxif_setconf(3, ifconf); /* chain 3: 2nd radio, bleeper channel 3, all SF */ + + /* set configuration for Lora 'stand alone' channel */ + ifconf.enable = true; + ifconf.rf_chain = 0; + ifconf.freq_hz = 187500; + ifconf.bandwidth = BW_125KHZ; + ifconf.datarate = DR_LORA_SF10; + lgw_rxif_setconf(8, ifconf); /* chain 8: bleeper channel 4, SF10 only */ + + /* set configuration for TX packet */ + memset(&txs, 0, sizeof(txs)); + txs.freq_hz = 866250000; + txs.tx_mode = IMMEDIATE; + txs.modulation = MOD_LORA; + txs.bandwidth = BW_250KHZ; + txs.datarate = DR_LORA_SF10; + txs.coderate = CR_LORA_4_5; + txs.payload = "TX.TEST.LORA.GATEWAY"; + txs.size = 20; + txs.invert_pol = false; + + /* connect, configure and start the Lora gateway */ + lgw_start(); + + while ((quit_sig != 1) && (exit_sig != 1)) { + /* fetch N packets */ + nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt); + + if (nb_pkt == 0) { + wait_ms(300); + } else { + printf("\nLora gateway, %d packets received:\n\n", nb_pkt); + /* display received packets */ + for(i=0; i < nb_pkt; ++i) { + p = &rxpkt[i]; + printf("---\nPkt #%d >>", i+1); + if (p->status == STAT_CRC_OK) { + printf(" if_chain:%2d", p->if_chain); + printf(" tstamp:%010u", p->count_us); + printf(" size:%3u", p->size); + switch (p-> modulation) { + case MOD_LORA: printf(" Lora"); break; + case MOD_FSK: printf(" FSK"); break; + case MOD_GFSK: printf(" GFSK"); break; + default: printf(" modulation?"); + } + switch (p->datarate) { + case DR_LORA_SF7: printf(" SF7"); break; + case DR_LORA_SF8: printf(" SF8"); break; + case DR_LORA_SF9: printf(" SF9"); break; + case DR_LORA_SF10: printf(" SF10"); break; + case DR_LORA_SF11: printf(" SF11"); break; + case DR_LORA_SF12: printf(" SF12"); break; + default: printf(" datarate?"); + } + switch (p->coderate) { + case CR_LORA_4_5: printf(" CR1(4/5)"); break; + case CR_LORA_4_6: printf(" CR2(2/3)"); break; + case CR_LORA_4_7: printf(" CR3(4/7)"); break; + case CR_LORA_4_8: printf(" CR4(1/2)"); break; + default: printf(" coderate?"); + } + printf("\n"); + printf(" RSSI:%+6.1f SNR:%+5.1f (min:%+5.1f, max:%+5.1f) payload:\n", p->rssi, p->snr, p->snr_min, p->snr_max); + for (j = 0; j < p->size; ++j) { + printf(" %02X", p->payload[j]); + } + printf(" #\n"); + } else if (p->status == STAT_CRC_BAD) { + printf(" if_chain:%2d", p->if_chain); + printf(" tstamp:%010u", p->count_us); + printf(" size:%3u\n", p->size); + printf(" CRC error, damaged packet\n\n"); + } else if (p->status == STAT_NO_CRC){ + printf(" if_chain:%2d", p->if_chain); + printf(" tstamp:%010u", p->count_us); + printf(" size:%3u\n", p->size); + printf(" no CRC\n\n"); + } else { + printf(" if_chain:%2d", p->if_chain); + printf(" tstamp:%010u", p->count_us); + printf(" size:%3u\n", p->size); + printf(" invalid status ?!?\n\n"); + } + } + + /* free the memory used for RX payload(s) */ + for(i=0; i < nb_pkt; ++i) { + free(rxpkt[i].payload); + } + } + + /* send a packet every X loop */ + if (tx_cnt >= 5) { + tx_cnt = 0; + + txs.rf_chain = tx_path; /* alternate between path A and B */ + i = lgw_send(txs); + printf("Packet sent, rf path %d, status %d\n", txs.rf_chain, i); + + tx_path = (tx_path+1) % 2; + } else { + ++tx_cnt; + } + } + + if (exit_sig == 1) { + /* clean up before leaving */ + lgw_stop(); + } + + printf("End of test for loragw_hal.c\n"); + return 0; } /* --- EOF ------------------------------------------------------------------ */ diff --git a/loragw_hal/test/test_loragw_reg.c b/loragw_hal/test/test_loragw_reg.c index 745ec89..2b80109 100644 --- a/loragw_hal/test/test_loragw_reg.c +++ b/loragw_hal/test/test_loragw_reg.c @@ -1,13 +1,13 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - Minimum test program for the loragw_spi 'library' + Minimum test program for the loragw_spi 'library' */ @@ -22,110 +22,110 @@ Description: /* -------------------------------------------------------------------------- */ /* --- MAIN FUNCTION -------------------------------------------------------- */ -#define BURST_TEST_LENGTH 8192 +#define BURST_TEST_LENGTH 8192 int main(int argc, char **argv) { - int32_t read_value, test_value; - uint16_t lfsr; - uint8_t burst_buffout[BURST_TEST_LENGTH]; - uint8_t burst_buffin[BURST_TEST_LENGTH]; - int i; - - printf("Beginning of test for loragw_reg.c\n"); - - lgw_connect(); - /* 2 SPI transactions: - -> 0x80 0x00 <- 0x00 0x00 forcing page 0 - -> 0x01 0x00 <- 0x00 0x64 checking version - */ - - /* --- READ TEST --- */ - - lgw_reg_w(LGW_SOFT_RESET, 1); - lgw_reg_check(stdout); - - /* --- READ/WRITE COHERENCY TEST --- */ - - /* 8b unsigned */ - test_value = 197; /* 11000101b */ - lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value); - lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); - printf("IMPLICIT_PAYLOAD_LENGHT = %d (should be %d)\n", read_value, test_value); - - /* 8b signed */ - /* NO SUCH REG AVAILABLE */ - // /* RADIO_SELECT is normally unsigned, modify it manually in loragw_reg.c */ - // test_value = -59; /* 11000101b */ - // lgw_reg_w(LGW_RADIO_SELECT, test_value); - // lgw_reg_r(LGW_RADIO_SELECT, &read_value); - // printf("RADIO_SELECT = %d (should be %d)\n", read_value, test_value); - - /* less than 8b, with offset, unsigned */ - test_value = 11; /* 1011b */ - lgw_reg_w(LGW_FRAME_SYNCH_PEAK2_POS, test_value); - lgw_reg_r(LGW_FRAME_SYNCH_PEAK2_POS, &read_value); - printf("FRAME_SYNCH_PEAK2_POS = %d (should be %d)\n", read_value, test_value); - - /* less than 8b, with offset, signed */ - /* NO SUCH REG AVAILABLE */ - // /* MBWSSF_FRAME_SYNCH_PEAK2_POS is normally unsigned, modify it manually in loragw_reg.c */ - // test_value = -5; /* 1011b */ - // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS, test_value); - // lgw_reg_r(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS, &read_value); - // printf("MBWSSF_FRAME_SYNCH_PEAK2_POS = %d (should be %d)\n", read_value, test_value); - - /* 16b unsigned */ - test_value = 49253; /* 11000000 01100101b */ - lgw_reg_w(LGW_PREAMBLE_SYMB1_NB, test_value); - lgw_reg_r(LGW_PREAMBLE_SYMB1_NB, &read_value); - printf("PREAMBLE_SYMB1_NB = %d (should be %d)\n", read_value, test_value); - - /* 16b signed */ - /* NO SUCH REG AVAILABLE */ - // /* CAPTURE_PERIOD is normally unsigned, modify it manually in loragw_reg.c */ - // test_value = -16283; /* 11000000 01100101b */ - // lgw_reg_w(LGW_CAPTURE_PERIOD, test_value); - // lgw_reg_r(LGW_CAPTURE_PERIOD, &read_value); - // printf("CAPTURE_PERIOD = %d (should be %d)\n", read_value, test_value); - - /* between 8b and 16b, unsigned */ - test_value = 3173; /* 1100 01100101b */ - lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4, test_value); - lgw_reg_r(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4, &read_value); - printf("ADJUST_MODEM_START_OFFSET_SF12_RDX4 = %d (should be %d)\n", read_value, test_value); - - /* between 8b and 16b, signed */ - test_value = -1947; /* 11000 01100101b */ - lgw_reg_w(LGW_IF_FREQ_1, test_value); - lgw_reg_r(LGW_IF_FREQ_1, &read_value); - printf("IF_FREQ_1 = %d (should be %d)\n", read_value, test_value); - - /* --- BURST WRITE AND READ TEST --- */ - - /* initialize data for SPI test */ - lfsr = 0xFFFF; - for(i=0; i<BURST_TEST_LENGTH; ++i) { - burst_buffout[i] = (uint8_t)(lfsr ^ (lfsr >> 4)); - /* printf("%05d # 0x%04x 0x%02x\n", i, lfsr, burst_buffout[i]); */ - lfsr = (lfsr & 1) ? ((lfsr >> 1) ^ 0x8679) : (lfsr >> 1); - } - - lgw_reg_wb(LGW_TX_DATA_BUF_DATA, burst_buffout, 256); - lgw_reg_rb(LGW_RX_DATA_BUF_DATA, burst_buffin, 256); - - /* impossible to check in software, - RX_DATA_BUF_DATA is read-only, - TX_DATA_BUF_DATA is write only, - use a logic analyser */ - - /* --- END OF TEST --- */ - - lgw_disconnect(); - /* no SPI transaction */ - - printf("End of test for loragw_reg.c\n"); - return 0; + int32_t read_value, test_value; + uint16_t lfsr; + uint8_t burst_buffout[BURST_TEST_LENGTH]; + uint8_t burst_buffin[BURST_TEST_LENGTH]; + int i; + + printf("Beginning of test for loragw_reg.c\n"); + + lgw_connect(); + /* 2 SPI transactions: + -> 0x80 0x00 <- 0x00 0x00 forcing page 0 + -> 0x01 0x00 <- 0x00 0x64 checking version + */ + + /* --- READ TEST --- */ + + lgw_reg_w(LGW_SOFT_RESET, 1); + lgw_reg_check(stdout); + + /* --- READ/WRITE COHERENCY TEST --- */ + + /* 8b unsigned */ + test_value = 197; /* 11000101b */ + lgw_reg_w(LGW_IMPLICIT_PAYLOAD_LENGHT, test_value); + lgw_reg_r(LGW_IMPLICIT_PAYLOAD_LENGHT, &read_value); + printf("IMPLICIT_PAYLOAD_LENGHT = %d (should be %d)\n", read_value, test_value); + + /* 8b signed */ + /* NO SUCH REG AVAILABLE */ + // /* RADIO_SELECT is normally unsigned, modify it manually in loragw_reg.c */ + // test_value = -59; /* 11000101b */ + // lgw_reg_w(LGW_RADIO_SELECT, test_value); + // lgw_reg_r(LGW_RADIO_SELECT, &read_value); + // printf("RADIO_SELECT = %d (should be %d)\n", read_value, test_value); + + /* less than 8b, with offset, unsigned */ + test_value = 11; /* 1011b */ + lgw_reg_w(LGW_FRAME_SYNCH_PEAK2_POS, test_value); + lgw_reg_r(LGW_FRAME_SYNCH_PEAK2_POS, &read_value); + printf("FRAME_SYNCH_PEAK2_POS = %d (should be %d)\n", read_value, test_value); + + /* less than 8b, with offset, signed */ + /* NO SUCH REG AVAILABLE */ + // /* MBWSSF_FRAME_SYNCH_PEAK2_POS is normally unsigned, modify it manually in loragw_reg.c */ + // test_value = -5; /* 1011b */ + // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS, test_value); + // lgw_reg_r(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS, &read_value); + // printf("MBWSSF_FRAME_SYNCH_PEAK2_POS = %d (should be %d)\n", read_value, test_value); + + /* 16b unsigned */ + test_value = 49253; /* 11000000 01100101b */ + lgw_reg_w(LGW_PREAMBLE_SYMB1_NB, test_value); + lgw_reg_r(LGW_PREAMBLE_SYMB1_NB, &read_value); + printf("PREAMBLE_SYMB1_NB = %d (should be %d)\n", read_value, test_value); + + /* 16b signed */ + /* NO SUCH REG AVAILABLE */ + // /* CAPTURE_PERIOD is normally unsigned, modify it manually in loragw_reg.c */ + // test_value = -16283; /* 11000000 01100101b */ + // lgw_reg_w(LGW_CAPTURE_PERIOD, test_value); + // lgw_reg_r(LGW_CAPTURE_PERIOD, &read_value); + // printf("CAPTURE_PERIOD = %d (should be %d)\n", read_value, test_value); + + /* between 8b and 16b, unsigned */ + test_value = 3173; /* 1100 01100101b */ + lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4, test_value); + lgw_reg_r(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4, &read_value); + printf("ADJUST_MODEM_START_OFFSET_SF12_RDX4 = %d (should be %d)\n", read_value, test_value); + + /* between 8b and 16b, signed */ + test_value = -1947; /* 11000 01100101b */ + lgw_reg_w(LGW_IF_FREQ_1, test_value); + lgw_reg_r(LGW_IF_FREQ_1, &read_value); + printf("IF_FREQ_1 = %d (should be %d)\n", read_value, test_value); + + /* --- BURST WRITE AND READ TEST --- */ + + /* initialize data for SPI test */ + lfsr = 0xFFFF; + for(i=0; i<BURST_TEST_LENGTH; ++i) { + burst_buffout[i] = (uint8_t)(lfsr ^ (lfsr >> 4)); + /* printf("%05d # 0x%04x 0x%02x\n", i, lfsr, burst_buffout[i]); */ + lfsr = (lfsr & 1) ? ((lfsr >> 1) ^ 0x8679) : (lfsr >> 1); + } + + lgw_reg_wb(LGW_TX_DATA_BUF_DATA, burst_buffout, 256); + lgw_reg_rb(LGW_RX_DATA_BUF_DATA, burst_buffin, 256); + + /* impossible to check in software, + RX_DATA_BUF_DATA is read-only, + TX_DATA_BUF_DATA is write only, + use a logic analyser */ + + /* --- END OF TEST --- */ + + lgw_disconnect(); + /* no SPI transaction */ + + printf("End of test for loragw_reg.c\n"); + return 0; } /* --- EOF ------------------------------------------------------------------ */ diff --git a/loragw_hal/test/test_loragw_spi.c b/loragw_hal/test/test_loragw_spi.c index 76dbeef..c5ab45b 100644 --- a/loragw_hal/test/test_loragw_spi.c +++ b/loragw_hal/test/test_loragw_spi.c @@ -1,14 +1,14 @@ /* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| ©2013 Semtech-Cycleo Description: - Minimum test program for the loragw_spi 'library' - Use logic analyser to check the results. + Minimum test program for the loragw_spi 'library' + Use logic analyser to check the results. */ @@ -35,35 +35,35 @@ Description: int main(int argc, char **argv) { - int i; - int spi_device; - uint8_t data; - uint8_t dataout[BURST_TEST_SIZE]; - uint8_t datain[BURST_TEST_SIZE]; - - for (i = 0; i < BURST_TEST_SIZE; ++i) { - dataout[i] = 0x30 + (i % 10); /* ASCCI code for 0 -> 9 */ - datain[i] = 0x23; /* garbage data, to be overwritten by received data */ - } - - printf("Beginning of test for loragw_spi.c\n"); - lgw_spi_open(&spi_device); - - /* normal R/W test */ - lgw_spi_w(spi_device, 0xAA, 0x96); - lgw_spi_r(spi_device, 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)); - - /* display results */ - printf("data received: %d\n",data); - - lgw_spi_close(spi_device); - printf("End of test for loragw_spi.c\n"); - - return 0; + int i; + int spi_device; + uint8_t data; + uint8_t dataout[BURST_TEST_SIZE]; + uint8_t datain[BURST_TEST_SIZE]; + + for (i = 0; i < BURST_TEST_SIZE; ++i) { + dataout[i] = 0x30 + (i % 10); /* ASCCI code for 0 -> 9 */ + datain[i] = 0x23; /* garbage data, to be overwritten by received data */ + } + + printf("Beginning of test for loragw_spi.c\n"); + lgw_spi_open(&spi_device); + + /* normal R/W test */ + lgw_spi_w(spi_device, 0xAA, 0x96); + lgw_spi_r(spi_device, 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)); + + /* display results */ + printf("data received: %d\n",data); + + lgw_spi_close(spi_device); + printf("End of test for loragw_spi.c\n"); + + return 0; } /* --- EOF ------------------------------------------------------------------ */ |