summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSylvain Miermont <smiermont@semtech.com>2013-07-03 17:53:18 +0200
committerSylvain Miermont <smiermont@semtech.com>2013-10-23 10:16:59 +0200
commit1361e7215cd0eb3b38faff1c403cb3077e41b2be (patch)
treec52471c65b0a40b081b7de6a8570757f85c71704
parent3357493e096fc0bd4767d1a3cc0cb7e3e52a4f53 (diff)
downloadlora_gateway-1361e7215cd0eb3b38faff1c403cb3077e41b2be.tar.gz
lora_gateway-1361e7215cd0eb3b38faff1c403cb3077e41b2be.tar.bz2
lora_gateway-1361e7215cd0eb3b38faff1c403cb3077e41b2be.zip
Release Candidate 2v0.rc2
- code cleanup and formating - variable and constants renaming - TX polarity management - fixed bugs thanks to Joe Knapp feedback
-rw-r--r--loragw_hal/README109
-rw-r--r--loragw_hal/inc/loragw_aux.h6
-rw-r--r--loragw_hal/inc/loragw_hal.h205
-rw-r--r--loragw_hal/inc/loragw_reg.h20
-rw-r--r--loragw_hal/inc/loragw_spi.h22
-rw-r--r--loragw_hal/src/agc_fw.var6
-rw-r--r--loragw_hal/src/arb_fw.var6
-rw-r--r--loragw_hal/src/loragw_aux.c44
-rw-r--r--loragw_hal/src/loragw_hal.c1667
-rw-r--r--loragw_hal/src/loragw_reg.c1236
-rw-r--r--loragw_hal/src/loragw_spi.c448
-rw-r--r--loragw_hal/test/test_loragw_hal.c397
-rw-r--r--loragw_hal/test/test_loragw_reg.c208
-rw-r--r--loragw_hal/test/test_loragw_spi.c66
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 ------------------------------------------------------------------ */