Damian Gabino / picoGW_mcu
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers loragw_hal.cpp Source File

loragw_hal.cpp

00001 /*
00002  / _____)             _              | |
00003 ( (____  _____ ____ _| |_ _____  ____| |__
00004  \____ \| ___ |    (_   _) ___ |/ ___)  _ \
00005  _____) ) ____| | | || |_| ____( (___| | | |
00006 (______/|_____)_|_|_| \__)_____)\____)_| |_|
00007 (C)2017 Semtech-Cycleo
00008 
00009 Description:
00010 LoRa concentrator Hardware Abstraction Layer
00011 
00012 License: Revised BSD License, see LICENSE.TXT file include in the project
00013 */
00014 
00015 
00016 /* -------------------------------------------------------------------------- */
00017 /* --- DEPENDANCIES --------------------------------------------------------- */
00018 
00019 #include <stdint.h>     /* C99 types */
00020 #include <stdbool.h>    /* bool type */
00021 #include <stdio.h>      /* printf fprintf */
00022 #include <string.h>     /* memcpy */
00023 #include <math.h>       /* pow, cell */
00024 #include "loragw_reg.h"
00025 #include "loragw_hal.h"
00026 #include "loragw_radio.h"
00027 #include "board.h"
00028 
00029 /* -------------------------------------------------------------------------- */
00030 /* --- PRIVATE MACROS ------------------------------------------------------- */
00031 
00032 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
00033 #if DEBUG_HAL == 1
00034 #define DEBUG_MSG(str)                pc.printf(str)
00035 #define DEBUG_PRINTF(fmt, args...)    pc.printf("%s:%d: "fmt, __FUNCTION__, __LINE__, args)
00036 #define DEBUG_ARRAY(a,b,c)           for(a=0;a!=0;){}
00037 #define CHECK_NULL(a)                if(a==NULL){return LGW_HAL_ERROR;}
00038 #else
00039 #define DEBUG_MSG(str)
00040 #define DEBUG_PRINTF(fmt, args...)
00041 #define DEBUG_ARRAY(a,b,c)            for(a=0;a!=0;){}
00042 #define CHECK_NULL(a)                 if(a==NULL){return LGW_HAL_ERROR;}
00043 #endif
00044 #define IF_HZ_TO_REG(f)     (f << 5)/15625
00045 #define SET_PPM_ON(bw,dr)   (((bw == BW_125KHZ) && ((dr == DR_LORA_SF11) || (dr == DR_LORA_SF12))) || ((bw == BW_250KHZ) && (dr == DR_LORA_SF12)))
00046 #define TRACE()
00047 
00048 /* -------------------------------------------------------------------------- */
00049 /* --- PRIVATE CONSTANTS & TYPES -------------------------------------------- */
00050 
00051 #define MCU_ARB             0
00052 #define MCU_AGC             1
00053 #define MCU_ARB_FW_BYTE     8192 /* size of the firmware IN BYTES (= twice the number of 14b words) */
00054 #define MCU_AGC_FW_BYTE     8192 /* size of the firmware IN BYTES (= twice the number of 14b words) */
00055 #define FW_VERSION_ADDR     0x20 /* Address of firmware version in data memory */
00056 #define FW_VERSION_CAL      2 /* Expected version of calibration firmware */
00057 #define FW_VERSION_AGC      4 /* Expected version of AGC firmware */
00058 #define FW_VERSION_ARB      1 /* Expected version of arbiter firmware */
00059 #define TX_METADATA_NB      16
00060 #define RX_METADATA_NB      16
00061 #define AGC_CMD_WAIT        16
00062 #define AGC_CMD_ABORT       17
00063 #define MIN_LORA_PREAMBLE   4
00064 #define STD_LORA_PREAMBLE   6
00065 #define MIN_FSK_PREAMBLE    3
00066 #define STD_FSK_PREAMBLE    5
00067 #define TX_START_DELAY      1500
00068 #define RSSI_MULTI_BIAS     -35 /* difference between "multi" modem RSSI offset and "stand-alone" modem RSSI offset */
00069 #define RSSI_FSK_POLY_0     60 /* polynomiam coefficients to linearize FSK RSSI */
00070 #define RSSI_FSK_POLY_1     1.5351
00071 #define RSSI_FSK_POLY_2     0.003
00072 #define LGW_RF_RX_BANDWIDTH_125KHZ  925000      /* for 125KHz channels */
00073 #define LGW_RF_RX_BANDWIDTH_250KHZ  1000000     /* for 250KHz channels */
00074 #define LGW_RF_RX_BANDWIDTH_500KHZ  1100000     /* for 500KHz channels */
00075 /* constant arrays defining hardware capability */
00076 const uint8_t ifmod_config[LGW_IF_CHAIN_NB] = LGW_IFMODEM_CONFIG;
00077 
00078 
00079 /* Version string, used to identify the library version/options once compiled */
00080 const char lgw_version_string[] = "Version: 0.1";// LIBLORAGW_VERSION ";";
00081 
00082 /* -------------------------------------------------------------------------- */
00083 /* --- PRIVATE VARIABLES ---------------------------------------------------- */
00084 
00085 static int32_t iqrxtab[4];
00086 
00087 /*
00088 The following static variables are the configuration set that the user can
00089 modify using rxrf_setconf, rxif_setconf and txgain_setconf functions.
00090 The functions _start and _send then use that set to configure the hardware.
00091 
00092 Parameters validity and coherency is verified by the _setconf functions and
00093 the _start and _send functions assume they are valid.
00094 */
00095 
00096 static bool rf_enable[LGW_RF_CHAIN_NB];
00097 static uint32_t rf_rx_freq[LGW_RF_CHAIN_NB]; /* absolute, in Hz */
00098 static float rf_rssi_offset[LGW_RF_CHAIN_NB];
00099 static bool rf_tx_enable[LGW_RF_CHAIN_NB];
00100 static enum lgw_radio_type_e rf_radio_type[LGW_RF_CHAIN_NB];
00101 static bool if_enable[LGW_IF_CHAIN_NB];
00102 static bool if_rf_chain[LGW_IF_CHAIN_NB]; /* for each IF, 0 -> radio A, 1 -> radio B */
00103 static int32_t if_freq[LGW_IF_CHAIN_NB]; /* relative to radio frequency, +/- in Hz */
00104 static uint8_t lora_multi_sfmask[LGW_MULTI_NB]; /* enables SF for LoRa 'multi' modems */
00105 static uint8_t lora_rx_bw; /* bandwidth setting for LoRa standalone modem */
00106 static uint8_t lora_rx_sf; /* spreading factor setting for LoRa standalone modem */
00107 static bool lora_rx_ppm_offset;
00108 static uint8_t fsk_rx_bw; /* bandwidth setting of FSK modem */
00109 static uint32_t fsk_rx_dr; /* FSK modem datarate in bauds */
00110 static uint8_t fsk_sync_word_size = 3; /* default number of bytes for FSK sync word */
00111 static uint64_t fsk_sync_word = 0xC194C1; /* default FSK sync word (ALIGNED RIGHT, MSbit first) */
00112 static bool lorawan_public = true;
00113 
00114 static struct lgw_tx_gain_lut_s txgain_lut = {
00115     .size  = 2,
00116     .lut[0] = {
00117         .dig_gain = 0,
00118         .pa_gain = 2,
00119         .dac_gain = 3,
00120         .mix_gain = 10,
00121         .rf_power = 14
00122     },
00123     .lut[1] = {
00124         .dig_gain = 0,
00125         .pa_gain = 3,
00126         .dac_gain = 3,
00127         .mix_gain = 14,
00128         .rf_power = 27
00129     }
00130 };
00131 
00132 /* TX I/Q imbalance coefficients for mixer gain = 8 to 15 */
00133 static int8_t cal_offset_a_i[16]; /* TX I offset for radio A */
00134 static int8_t cal_offset_a_q[16]; /* TX Q offset for radio A */
00135 static int8_t cal_offset_b_i[16]; /* TX I offset for radio B */
00136 static int8_t cal_offset_b_q[16]; /* TX Q offset for radio B */
00137 
00138 /* -------------------------------------------------------------------------- */
00139 /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
00140 
00141 void lgw_constant_adjust(void);
00142 int32_t lgw_sf_getval(int x);
00143 int32_t lgw_bw_getval(int x);
00144 int reset_firmware(uint8_t target);
00145 void calibration_save(void);
00146 void calibration_reload(void);
00147 
00148 /* -------------------------------------------------------------------------- */
00149 /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
00150 
00151 int reset_firmware(uint8_t target) {
00152     int reg_rst;
00153     int reg_sel;
00154 
00155     /* check parameters */
00156     if (target == MCU_ARB) {
00157         reg_rst = LGW_MCU_RST_0;
00158         reg_sel = LGW_MCU_SELECT_MUX_0;
00159     } else if (target == MCU_AGC) {
00160         reg_rst = LGW_MCU_RST_1;
00161         reg_sel = LGW_MCU_SELECT_MUX_1;
00162     } else {
00163         DEBUG_MSG("ERROR: NOT A VALID TARGET FOR RESETTING FIRMWARE\n");
00164         return -1;
00165     }
00166 
00167     /* reset the targeted MCU */
00168     lgw_reg_w(reg_rst, 1);
00169 
00170     /* set mux to access MCU program RAM and set address to 0 */
00171     lgw_reg_w(reg_sel, 0);
00172     lgw_reg_w(LGW_MCU_PROM_ADDR, 0);
00173 
00174     /* give back control of the MCU program ram to the MCU */
00175     lgw_reg_w(reg_sel, 1);
00176 
00177     return 0;
00178 }
00179 
00180 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00181 
00182 void lgw_constant_adjust(void) {
00183 
00184     /* I/Q path setup */
00185     // lgw_reg_w(LGW_RX_INVERT_IQ,0); /* default 0 */
00186     // lgw_reg_w(LGW_MODEM_INVERT_IQ,1); /* default 1 */
00187     // lgw_reg_w(LGW_CHIRP_INVERT_RX,1); /* default 1 */
00188     // lgw_reg_w(LGW_RX_EDGE_SELECT,0); /* default 0 */
00189     // lgw_reg_w(LGW_MBWSSF_MODEM_INVERT_IQ,0); /* default 0 */
00190     // lgw_reg_w(LGW_DC_NOTCH_EN,1); /* default 1 */
00191     lgw_reg_w(LGW_RSSI_BB_FILTER_ALPHA, 6); /* default 7 */
00192     lgw_reg_w(LGW_RSSI_DEC_FILTER_ALPHA, 7); /* default 5 */
00193     lgw_reg_w(LGW_RSSI_CHANN_FILTER_ALPHA, 7); /* default 8 */
00194     lgw_reg_w(LGW_RSSI_BB_DEFAULT_VALUE, 23); /* default 32 */
00195     lgw_reg_w(LGW_RSSI_CHANN_DEFAULT_VALUE, 85); /* default 100 */
00196     lgw_reg_w(LGW_RSSI_DEC_DEFAULT_VALUE, 66); /* default 100 */
00197     lgw_reg_w(LGW_DEC_GAIN_OFFSET, 7); /* default 8 */
00198     lgw_reg_w(LGW_CHAN_GAIN_OFFSET, 6); /* default 7 */
00199 
00200     /* Correlator setup */
00201     // lgw_reg_w(LGW_CORR_DETECT_EN,126); /* default 126 */
00202     // lgw_reg_w(LGW_CORR_NUM_SAME_PEAK,4); /* default 4 */
00203     // lgw_reg_w(LGW_CORR_MAC_GAIN,5); /* default 5 */
00204     // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF6,0); /* default 0 */
00205     // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF7,1); /* default 1 */
00206     // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF8,1); /* default 1 */
00207     // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF9,1); /* default 1 */
00208     // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF10,1); /* default 1 */
00209     // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF11,1); /* default 1 */
00210     // lgw_reg_w(LGW_CORR_SAME_PEAKS_OPTION_SF12,1); /* default 1 */
00211     // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF6,4); /* default 4 */
00212     // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF7,4); /* default 4 */
00213     // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF8,4); /* default 4 */
00214     // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF9,4); /* default 4 */
00215     // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF10,4); /* default 4 */
00216     // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF11,4); /* default 4 */
00217     // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF12,4); /* default 4 */
00218 
00219     /* LoRa 'multi' demodulators setup */
00220     // lgw_reg_w(LGW_PREAMBLE_SYMB1_NB,10); /* default 10 */
00221     // lgw_reg_w(LGW_FREQ_TO_TIME_INVERT,29); /* default 29 */
00222     // lgw_reg_w(LGW_FRAME_SYNCH_GAIN,1); /* default 1 */
00223     // lgw_reg_w(LGW_SYNCH_DETECT_TH,1); /* default 1 */
00224     // lgw_reg_w(LGW_ZERO_PAD,0); /* default 0 */
00225     lgw_reg_w(LGW_SNR_AVG_CST, 3); /* default 2 */
00226     if (lorawan_public) { /* LoRa network */
00227         lgw_reg_w(LGW_FRAME_SYNCH_PEAK1_POS, 3); /* default 1 */
00228         lgw_reg_w(LGW_FRAME_SYNCH_PEAK2_POS, 4); /* default 2 */
00229     } else { /* private network */
00230         lgw_reg_w(LGW_FRAME_SYNCH_PEAK1_POS, 1); /* default 1 */
00231         lgw_reg_w(LGW_FRAME_SYNCH_PEAK2_POS, 2); /* default 2 */
00232     }
00233 
00234     // lgw_reg_w(LGW_PREAMBLE_FINE_TIMING_GAIN,1); /* default 1 */
00235     // lgw_reg_w(LGW_ONLY_CRC_EN,1); /* default 1 */
00236     // lgw_reg_w(LGW_PAYLOAD_FINE_TIMING_GAIN,2); /* default 2 */
00237     // lgw_reg_w(LGW_TRACKING_INTEGRAL,0); /* default 0 */
00238     // lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_RDX8,0); /* default 0 */
00239     // lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4,4092); /* default 4092 */
00240     // lgw_reg_w(LGW_MAX_PAYLOAD_LEN,255); /* default 255 */
00241 
00242     /* LoRa standalone 'MBWSSF' demodulator setup */
00243     // lgw_reg_w(LGW_MBWSSF_PREAMBLE_SYMB1_NB,10); /* default 10 */
00244     // lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_INVERT,29); /* default 29 */
00245     // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_GAIN,1); /* default 1 */
00246     // lgw_reg_w(LGW_MBWSSF_SYNCH_DETECT_TH,1); /* default 1 */
00247     // lgw_reg_w(LGW_MBWSSF_ZERO_PAD,0); /* default 0 */
00248     if (lorawan_public) { /* LoRa network */
00249         lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK1_POS, 3); /* default 1 */
00250         lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS, 4); /* default 2 */
00251     } else {
00252         lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK1_POS, 1); /* default 1 */
00253         lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_PEAK2_POS, 2); /* default 2 */
00254     }
00255     // lgw_reg_w(LGW_MBWSSF_ONLY_CRC_EN,1); /* default 1 */
00256     // lgw_reg_w(LGW_MBWSSF_PAYLOAD_FINE_TIMING_GAIN,2); /* default 2 */
00257     // lgw_reg_w(LGW_MBWSSF_PREAMBLE_FINE_TIMING_GAIN,1); /* default 1 */
00258     // lgw_reg_w(LGW_MBWSSF_TRACKING_INTEGRAL,0); /* default 0 */
00259     // lgw_reg_w(LGW_MBWSSF_AGC_FREEZE_ON_DETECT,1); /* default 1 */
00260     lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_RDX4, 1); /* default 0 */
00261     lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4, 4094); /* default 4092 */
00262     lgw_reg_w(LGW_CORR_MAC_GAIN, 7); /* default 5 */
00263 
00264 
00265 
00266     /* FSK datapath setup */
00267     lgw_reg_w(LGW_FSK_RX_INVERT, 1); /* default 0 */
00268     lgw_reg_w(LGW_FSK_MODEM_INVERT_IQ, 1); /* default 0 */
00269 
00270     /* FSK demodulator setup */
00271     lgw_reg_w(LGW_FSK_RSSI_LENGTH, 4); /* default 0 */
00272     lgw_reg_w(LGW_FSK_PKT_MODE, 1); /* variable length, default 0 */
00273     lgw_reg_w(LGW_FSK_CRC_EN, 1); /* default 0 */
00274     lgw_reg_w(LGW_FSK_DCFREE_ENC, 2); /* default 0 */
00275     // lgw_reg_w(LGW_FSK_CRC_IBM,0); /* default 0 */
00276     lgw_reg_w(LGW_FSK_ERROR_OSR_TOL, 10); /* default 0 */
00277     lgw_reg_w(LGW_FSK_PKT_LENGTH, 255); /* max packet length in variable length mode */
00278     // lgw_reg_w(LGW_FSK_NODE_ADRS,0); /* default 0 */
00279     // lgw_reg_w(LGW_FSK_BROADCAST,0); /* default 0 */
00280     // lgw_reg_w(LGW_FSK_AUTO_AFC_ON,0); /* default 0 */
00281     lgw_reg_w(LGW_FSK_PATTERN_TIMEOUT_CFG, 128); /* sync timeout (allow 8 bytes preamble + 8 bytes sync word, default 0 */
00282 
00283     /* TX general parameters */
00284     lgw_reg_w(LGW_TX_START_DELAY, TX_START_DELAY); /* default 0 */
00285 
00286     /* TX LoRa */
00287     // lgw_reg_w(LGW_TX_MODE,0); /* default 0 */
00288     lgw_reg_w(LGW_TX_SWAP_IQ, 1); /* "normal" polarity; default 0 */
00289     if (lorawan_public) { /* LoRa network */
00290         lgw_reg_w(LGW_TX_FRAME_SYNCH_PEAK1_POS, 3); /* default 1 */
00291         lgw_reg_w(LGW_TX_FRAME_SYNCH_PEAK2_POS, 4); /* default 2 */
00292     } else { /* Private network */
00293         lgw_reg_w(LGW_TX_FRAME_SYNCH_PEAK1_POS, 1); /* default 1 */
00294         lgw_reg_w(LGW_TX_FRAME_SYNCH_PEAK2_POS, 2); /* default 2 */
00295     }
00296 
00297     /* TX FSK */
00298     // lgw_reg_w(LGW_FSK_TX_GAUSSIAN_EN,1); /* default 1 */
00299     lgw_reg_w(LGW_FSK_TX_GAUSSIAN_SELECT_BT, 2); /* Gaussian filter always on TX, default 0 */
00300     // lgw_reg_w(LGW_FSK_TX_PATTERN_EN,1); /* default 1 */
00301     // lgw_reg_w(LGW_FSK_TX_PREAMBLE_SEQ,0); /* default 0 */
00302 
00303     return;
00304 }
00305 
00306 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00307 
00308 int32_t lgw_bw_getval(int x) {
00309     switch (x) {
00310         case BW_500KHZ:
00311             return 500000;
00312         case BW_250KHZ:
00313             return 250000;
00314         case BW_125KHZ:
00315             return 125000;
00316         case BW_62K5HZ:
00317             return 62500;
00318         case BW_31K2HZ:
00319             return 31200;
00320         case BW_15K6HZ:
00321             return 15600;
00322         case BW_7K8HZ:
00323             return 7800;
00324         default:
00325             return -1;
00326     }
00327 }
00328 
00329 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00330 
00331 int32_t lgw_sf_getval(int x) {
00332     switch (x) {
00333         case DR_LORA_SF7:
00334             return 7;
00335         case DR_LORA_SF8:
00336             return 8;
00337         case DR_LORA_SF9:
00338             return 9;
00339         case DR_LORA_SF10:
00340             return 10;
00341         case DR_LORA_SF11:
00342             return 11;
00343         case DR_LORA_SF12:
00344             return 12;
00345         default:
00346             return -1;
00347     }
00348 }
00349 
00350 /* -------------------------------------------------------------------------- */
00351 /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
00352 
00353 int lgw_board_setconf(struct lgw_conf_board_s conf) {
00354 
00355     /* set internal config according to parameters */
00356     lorawan_public = conf.lorawan_public;
00357 
00358     DEBUG_PRINTF("Note: board configuration; lorawan_public:%d\n", lorawan_public);
00359 
00360     return LGW_HAL_SUCCESS;
00361 }
00362 
00363 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00364 
00365 int lgw_rxrf_setconf(uint8_t rf_chain, struct lgw_conf_rxrf_s conf) {
00366 
00367     /* check input range (segfault prevention) */
00368     if (rf_chain >= LGW_RF_CHAIN_NB) {
00369         DEBUG_MSG("ERROR: NOT A VALID RF_CHAIN NUMBER\n");
00370         return LGW_HAL_ERROR;
00371     }
00372 
00373     /* check if radio type is supported */
00374     if ((conf.type  != LGW_RADIO_TYPE_SX1255) && (conf.type  != LGW_RADIO_TYPE_SX1257)) {
00375         DEBUG_MSG("ERROR: NOT A VALID RADIO TYPE\n");
00376         return LGW_HAL_ERROR;
00377     }
00378 
00379     /* set internal config according to parameters */
00380     rf_enable[rf_chain] = conf.enable;
00381     rf_rx_freq[rf_chain] = conf.freq_hz ;
00382     rf_rssi_offset[rf_chain] = conf.rssi_offset ;
00383     rf_radio_type[rf_chain] = conf.type ;
00384     rf_tx_enable[rf_chain] = conf.tx_enable ;
00385 
00386     DEBUG_PRINTF("Note: rf_chain %d configuration; en:%d freq:%d rssi_offset:%f radio_type:%d tx_enable:%d tx_notch_freq:%u\n", rf_chain, rf_enable[rf_chain], rf_rx_freq[rf_chain], rf_rssi_offset[rf_chain], rf_radio_type[rf_chain], rf_tx_enable[rf_chain]);
00387 
00388     return LGW_HAL_SUCCESS;
00389 }
00390 
00391 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00392 
00393 int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) {
00394     int32_t bw_hz;
00395     uint32_t rf_rx_bandwidth;
00396 
00397     /* check input range (segfault prevention) */
00398     if (if_chain >= LGW_IF_CHAIN_NB) {
00399         DEBUG_PRINTF("ERROR: %d NOT A VALID IF_CHAIN NUMBER\n", if_chain);
00400         return LGW_HAL_ERROR;
00401     }
00402 
00403     /* if chain is disabled, don't care about most parameters */
00404     if (conf.enable == false) {
00405         if_enable[if_chain] = false;
00406         if_freq[if_chain] = 0;
00407         DEBUG_PRINTF("Note: if_chain %d disabled\n", if_chain);
00408         return LGW_HAL_SUCCESS;
00409     }
00410 
00411     /* check 'general' parameters */
00412     if (ifmod_config[if_chain] == IF_UNDEFINED) {
00413         DEBUG_PRINTF("ERROR: IF CHAIN %d NOT CONFIGURABLE\n", if_chain);
00414     }
00415     if (conf.rf_chain  >= LGW_RF_CHAIN_NB) {
00416         DEBUG_MSG("ERROR: INVALID RF_CHAIN TO ASSOCIATE WITH A LORA_STD IF CHAIN\n");
00417         return LGW_HAL_ERROR;
00418     }
00419 
00420     switch (conf.bandwidth ) {
00421         case BW_250KHZ:
00422             rf_rx_bandwidth = LGW_RF_RX_BANDWIDTH_250KHZ;
00423             break;
00424         case BW_500KHZ:
00425             rf_rx_bandwidth = LGW_RF_RX_BANDWIDTH_500KHZ;
00426             break;
00427         default:
00428             rf_rx_bandwidth = LGW_RF_RX_BANDWIDTH_125KHZ;
00429             break;
00430     }
00431 
00432     bw_hz = lgw_bw_getval(conf.bandwidth );
00433     if ((conf.freq_hz  + ((bw_hz == -1) ? LGW_REF_BW : bw_hz) / 2) > ((int32_t)rf_rx_bandwidth / 2)) {
00434         DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO HIGH\n", conf.freq_hz );
00435         return LGW_HAL_ERROR;
00436     } else if ((conf.freq_hz  - ((bw_hz == -1) ? LGW_REF_BW : bw_hz) / 2) < -((int32_t)rf_rx_bandwidth / 2)) {
00437         DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO LOW\n", conf.freq_hz );
00438         return LGW_HAL_ERROR;
00439     }
00440 
00441     /* check parameters according to the type of IF chain + modem,
00442     fill default if necessary, and commit configuration if everything is OK */
00443     switch (ifmod_config[if_chain]) {
00444         case IF_LORA_STD:
00445             /* fill default parameters if needed */
00446             if (conf.bandwidth  == BW_UNDEFINED) {
00447                 conf.bandwidth  = BW_250KHZ;
00448             }
00449             if (conf.datarate  == DR_UNDEFINED) {
00450                 conf.datarate  = DR_LORA_SF9;
00451             }
00452             /* check BW & DR */
00453             if (!IS_LORA_BW(conf.bandwidth )) {
00454                 DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA_STD IF CHAIN\n");
00455                 return LGW_HAL_ERROR;
00456             }
00457             if (!IS_LORA_STD_DR(conf.datarate )) {
00458                 DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY LORA_STD IF CHAIN\n");
00459                 return LGW_HAL_ERROR;
00460             }
00461             /* set internal configuration  */
00462             if_enable[if_chain] = conf.enable;
00463             if_rf_chain[if_chain] = conf.rf_chain ;
00464             if_freq[if_chain] = conf.freq_hz ;
00465             lora_rx_bw = conf.bandwidth ;
00466             lora_rx_sf = (uint8_t)(DR_LORA_MULTI & conf.datarate ); /* filter SF out of the 7-12 range */
00467             if (SET_PPM_ON(conf.bandwidth , conf.datarate )) {
00468                 lora_rx_ppm_offset = true;
00469             } else {
00470                 lora_rx_ppm_offset = false;
00471             }
00472 
00473             DEBUG_PRINTF("Note: LoRa 'std' if_chain %d configuration; 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);
00474             break;
00475 
00476         case IF_LORA_MULTI:
00477             /* fill default parameters if needed */
00478             if (conf.bandwidth  == BW_UNDEFINED) {
00479                 conf.bandwidth  = BW_125KHZ;
00480             }
00481             if (conf.datarate  == DR_UNDEFINED) {
00482                 conf.datarate  = DR_LORA_MULTI;
00483             }
00484             /* check BW & DR */
00485             if (conf.bandwidth  != BW_125KHZ) {
00486                 DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA_MULTI IF CHAIN\n");
00487                 return LGW_HAL_ERROR;
00488             }
00489             if (!IS_LORA_MULTI_DR(conf.datarate )) {
00490                 DEBUG_MSG("ERROR: DATARATE(S) NOT SUPPORTED BY LORA_MULTI IF CHAIN\n");
00491                 return LGW_HAL_ERROR;
00492             }
00493             /* set internal configuration  */
00494             if_enable[if_chain] = conf.enable;
00495             if_rf_chain[if_chain] = conf.rf_chain ;
00496             if_freq[if_chain] = conf.freq_hz ;
00497             lora_multi_sfmask[if_chain] = (uint8_t)(DR_LORA_MULTI & conf.datarate ); /* filter SF out of the 7-12 range */
00498 
00499             DEBUG_PRINTF("Note: LoRa 'multi' if_chain %d configuration; en:%d freq:%d SF_mask:0x%02x\n", if_chain, if_enable[if_chain], if_freq[if_chain], lora_multi_sfmask[if_chain]);
00500             break;
00501 
00502         case IF_FSK_STD:
00503             /* fill default parameters if needed */
00504             if (conf.bandwidth  == BW_UNDEFINED) {
00505                 conf.bandwidth  = BW_250KHZ;
00506             }
00507             if (conf.datarate  == DR_UNDEFINED) {
00508                 conf.datarate  = 64000; /* default datarate */
00509             }
00510             /* check BW & DR */
00511             if (!IS_FSK_BW(conf.bandwidth )) {
00512                 DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY FSK IF CHAIN\n");
00513                 return LGW_HAL_ERROR;
00514             }
00515             if (!IS_FSK_DR(conf.datarate )) {
00516                 DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY FSK IF CHAIN\n");
00517                 return LGW_HAL_ERROR;
00518             }
00519             /* set internal configuration  */
00520             if_enable[if_chain] = conf.enable;
00521             if_rf_chain[if_chain] = conf.rf_chain ;
00522             if_freq[if_chain] = conf.freq_hz ;
00523             fsk_rx_bw = conf.bandwidth ;
00524             fsk_rx_dr = conf.datarate ;
00525             if (conf.sync_word  > 0) {
00526                 fsk_sync_word_size = conf.sync_word_size ;
00527                 fsk_sync_word = conf.sync_word ;
00528             }
00529             DEBUG_PRINTF("Note: FSK if_chain %d configuration; en:%d freq:%d bw:%d dr:%d (%d real dr) sync:0x%0*llX\n", if_chain, if_enable[if_chain], if_freq[if_chain], fsk_rx_bw, fsk_rx_dr, LGW_XTAL_FREQU / (LGW_XTAL_FREQU / fsk_rx_dr), 2 * fsk_sync_word_size, fsk_sync_word);
00530             break;
00531 
00532         default:
00533             DEBUG_PRINTF("ERROR: IF CHAIN %d TYPE NOT SUPPORTED\n", if_chain);
00534             return LGW_HAL_ERROR;
00535     }
00536 
00537     return LGW_HAL_SUCCESS;
00538 }
00539 
00540 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00541 
00542 int lgw_txgain_setconf(struct lgw_tx_gain_lut_s *conf) {
00543     int i;
00544 
00545     /* Check LUT size */
00546     if ((conf->size  < 1) || (conf->size  > TX_GAIN_LUT_SIZE_MAX)) {
00547         DEBUG_PRINTF("ERROR: TX gain LUT must have at least one entry and  maximum %d entries\n", TX_GAIN_LUT_SIZE_MAX);
00548         return LGW_HAL_ERROR;
00549     }
00550 
00551     txgain_lut.size  = conf->size ;
00552 
00553     for (i = 0; i < txgain_lut.size ; i++) {
00554         /* Check gain range */
00555         if (conf->lut[i].dig_gain > 3) {
00556             DEBUG_MSG("ERROR: TX gain LUT: SX1308 digital gain must be between 0 and 3\n");
00557             return LGW_HAL_ERROR;
00558         }
00559         if (conf->lut[i].dac_gain  != 3) {
00560             DEBUG_MSG("ERROR: TX gain LUT: SX1257 DAC gains != 3 are not supported\n");
00561             return LGW_HAL_ERROR;
00562         }
00563         if (conf->lut[i].mix_gain  > 15) {
00564             DEBUG_MSG("WARNING: TX gain LUT: SX1257 mixer gain must not exceed 15\n");
00565             return LGW_HAL_ERROR;
00566         }
00567         if (conf->lut[i].pa_gain  > 3) {
00568             DEBUG_MSG("ERROR: TX gain LUT: External PA gain must not exceed 3\n");
00569             return LGW_HAL_ERROR;
00570         }
00571 
00572         /* Set internal LUT */
00573         txgain_lut.lut[i].dig_gain = conf->lut[i].dig_gain;
00574         txgain_lut.lut[i].dac_gain  = conf->lut[i].dac_gain ;
00575         txgain_lut.lut[i].mix_gain  = conf->lut[i].mix_gain ;
00576         txgain_lut.lut[i].pa_gain  = conf->lut[i].pa_gain ;
00577         txgain_lut.lut[i].rf_power  = conf->lut[i].rf_power ;
00578     }
00579 
00580     return LGW_HAL_SUCCESS;
00581 }
00582 
00583 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00584 
00585 int lgw_start(void) {
00586     int i;
00587     uint32_t x;
00588     uint8_t radio_select;
00589     int32_t read_val;
00590     uint8_t load_val;
00591     uint8_t fw_version;
00592     uint64_t fsk_sync_word_reg;
00593     int DELAYSTART = 1;
00594 
00595     /* Enable clocks */
00596     lgw_reg_w(LGW_GLOBAL_EN, 1);
00597     lgw_reg_w(LGW_CLK32M_EN, 1);
00598 
00599     /* Compute counter offset to be applied to SX1308 internal counter on receive and send */
00600     Sx1308.offtmstpstm32 = Sx1308.timerstm32ref.read_us() - Sx1308.offtmstpstm32ref;
00601 
00602     /* Set all GPIOs as output RXON/TXON*/
00603     lgw_reg_w(LGW_GPIO_MODE, 31);
00604     lgw_reg_w(LGW_GPIO_SELECT_OUTPUT, 0);
00605 
00606     /* select calibration command */
00607     calibration_reload();
00608 
00609     /* load adjusted parameters */
00610     lgw_constant_adjust();
00611 
00612     /* Sanity check for RX frequency */
00613     if (rf_rx_freq[0] == 0) {
00614         DEBUG_MSG("ERROR: wrong configuration, rf_rx_freq[0] is not set\n");
00615         return LGW_HAL_ERROR;
00616     }
00617 
00618     /* Freq-to-time-drift calculation */
00619     //float ftemp=(409600 / (rf_rx_freq[0] >> 1))*10000;
00620     float ftemp = (4096 * 2) / (rf_rx_freq[0] / 1000000);
00621     x = (uint32_t)ftemp; /* dividend: (4*2048*1000000) >> 1, rescaled to avoid 32b overflow */
00622     x = (x > 63) ? 63 : x; /* saturation */
00623     lgw_reg_w(LGW_FREQ_TO_TIME_DRIFT, x); /* default 9 */
00624 
00625     //ftemp=(409600 / (rf_rx_freq[0] >> 3))*10000; /* dividend: (16*2048*1000000) >> 3, rescaled to avoid 32b overflow */
00626     ftemp = (4096 * 8) / (rf_rx_freq[0] / 1000000);
00627     x = (uint32_t)ftemp;
00628     x = (x > 63) ? 63 : x; /* saturation */
00629     lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_DRIFT, x); /* default 36 */
00630 
00631     /* configure LoRa 'multi' demodulators aka. LoRa 'sensor' channels (IF0-3) */
00632     radio_select = 0; /* IF mapping to radio A/B (per bit, 0=A, 1=B) */
00633     for (i = 0; i < LGW_MULTI_NB; ++i) {
00634         radio_select += (if_rf_chain[i] == 1 ? 1 << i : 0); /* transform bool array into binary word */
00635     }
00636     /*
00637     lgw_reg_w(LGW_RADIO_SELECT, radio_select);
00638     LGW_RADIO_SELECT is used for communication with the firmware, "radio_select"
00639     will be loaded in LGW_RADIO_SELECT at the end of start procedure.
00640     */
00641 
00642     lgw_reg_w(LGW_IF_FREQ_0, IF_HZ_TO_REG(if_freq[0])); /* default -384 */
00643     lgw_reg_w(LGW_IF_FREQ_1, IF_HZ_TO_REG(if_freq[1])); /* default -128 */
00644     lgw_reg_w(LGW_IF_FREQ_2, IF_HZ_TO_REG(if_freq[2])); /* default 128 */
00645     lgw_reg_w(LGW_IF_FREQ_3, IF_HZ_TO_REG(if_freq[3])); /* default 384 */
00646     lgw_reg_w(LGW_IF_FREQ_4, IF_HZ_TO_REG(if_freq[4])); /* default -384 */
00647     lgw_reg_w(LGW_IF_FREQ_5, IF_HZ_TO_REG(if_freq[5])); /* default -128 */
00648     lgw_reg_w(LGW_IF_FREQ_6, IF_HZ_TO_REG(if_freq[6])); /* default 128 */
00649     lgw_reg_w(LGW_IF_FREQ_7, IF_HZ_TO_REG(if_freq[7])); /* default 384 */
00650     lgw_reg_w(LGW_CORR0_DETECT_EN, (if_enable[0] == true) ? lora_multi_sfmask[0] : 0); /* default 0 */
00651     lgw_reg_w(LGW_CORR1_DETECT_EN, (if_enable[1] == true) ? lora_multi_sfmask[1] : 0); /* default 0 */
00652     lgw_reg_w(LGW_CORR2_DETECT_EN, (if_enable[2] == true) ? lora_multi_sfmask[2] : 0); /* default 0 */
00653     lgw_reg_w(LGW_CORR3_DETECT_EN, (if_enable[3] == true) ? lora_multi_sfmask[3] : 0); /* default 0 */
00654     lgw_reg_w(LGW_CORR4_DETECT_EN, (if_enable[4] == true) ? lora_multi_sfmask[4] : 0); /* default 0 */
00655     lgw_reg_w(LGW_CORR5_DETECT_EN, (if_enable[5] == true) ? lora_multi_sfmask[5] : 0); /* default 0 */
00656     lgw_reg_w(LGW_CORR6_DETECT_EN, (if_enable[6] == true) ? lora_multi_sfmask[6] : 0); /* default 0 */
00657     lgw_reg_w(LGW_CORR7_DETECT_EN, (if_enable[7] == true) ? lora_multi_sfmask[7] : 0); /* default 0 */
00658     lgw_reg_w(LGW_PPM_OFFSET, 0x60); /* as the threshold is 16ms, use 0x60 to enable ppm_offset for SF12 and SF11 @125kHz*/
00659     lgw_reg_w(LGW_CONCENTRATOR_MODEM_ENABLE, 1); /* default 0 */
00660 
00661     /* configure LoRa 'stand-alone' modem (IF8) */
00662     lgw_reg_w(LGW_IF_FREQ_8, IF_HZ_TO_REG(if_freq[8])); /* MBWSSF modem (default 0) */
00663     if (if_enable[8] == true) {
00664         lgw_reg_w(LGW_MBWSSF_RADIO_SELECT, if_rf_chain[8]);
00665         switch (lora_rx_bw) {
00666             case BW_125KHZ:
00667                 lgw_reg_w(LGW_MBWSSF_MODEM_BW, 0);
00668                 break;
00669             case BW_250KHZ:
00670                 lgw_reg_w(LGW_MBWSSF_MODEM_BW, 1);
00671                 break;
00672             case BW_500KHZ:
00673                 lgw_reg_w(LGW_MBWSSF_MODEM_BW, 2);
00674                 break;
00675             default:
00676                 DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", lora_rx_bw);
00677                 return LGW_HAL_ERROR;
00678         }
00679         switch (lora_rx_sf) {
00680             case DR_LORA_SF7:
00681                 lgw_reg_w(LGW_MBWSSF_RATE_SF, 7);
00682                 break;
00683             case DR_LORA_SF8:
00684                 lgw_reg_w(LGW_MBWSSF_RATE_SF, 8);
00685                 break;
00686             case DR_LORA_SF9:
00687                 lgw_reg_w(LGW_MBWSSF_RATE_SF, 9);
00688                 break;
00689             case DR_LORA_SF10:
00690                 lgw_reg_w(LGW_MBWSSF_RATE_SF, 10);
00691                 break;
00692             case DR_LORA_SF11:
00693                 lgw_reg_w(LGW_MBWSSF_RATE_SF, 11);
00694                 break;
00695             case DR_LORA_SF12:
00696                 lgw_reg_w(LGW_MBWSSF_RATE_SF, 12);
00697                 break;
00698             default:
00699                 DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", lora_rx_sf);
00700                 return LGW_HAL_ERROR;
00701         }
00702         lgw_reg_w(LGW_MBWSSF_PPM_OFFSET, lora_rx_ppm_offset); /* default 0 */
00703         lgw_reg_w(LGW_MBWSSF_MODEM_ENABLE, 1); /* default 0 */
00704     } else {
00705         lgw_reg_w(LGW_MBWSSF_MODEM_ENABLE, 0);
00706     }
00707 
00708     /* configure FSK modem (IF9) */
00709     lgw_reg_w(LGW_IF_FREQ_9, IF_HZ_TO_REG(if_freq[9])); /* FSK modem, default 0 */
00710     lgw_reg_w(LGW_FSK_PSIZE, fsk_sync_word_size - 1);
00711     lgw_reg_w(LGW_FSK_TX_PSIZE, fsk_sync_word_size - 1);
00712     fsk_sync_word_reg = fsk_sync_word << (8 * (8 - fsk_sync_word_size));
00713     lgw_reg_w(LGW_FSK_REF_PATTERN_LSB, (uint32_t)(0xFFFFFFFF & fsk_sync_word_reg));
00714     lgw_reg_w(LGW_FSK_REF_PATTERN_MSB, (uint32_t)(0xFFFFFFFF & (fsk_sync_word_reg >> 32)));
00715     if (if_enable[9] == true) {
00716         lgw_reg_w(LGW_FSK_RADIO_SELECT, if_rf_chain[9]);
00717         lgw_reg_w(LGW_FSK_BR_RATIO, LGW_XTAL_FREQU / fsk_rx_dr); /* setting the dividing ratio for datarate */
00718         lgw_reg_w(LGW_FSK_CH_BW_EXPO, fsk_rx_bw);
00719         lgw_reg_w(LGW_FSK_MODEM_ENABLE, 1); /* default 0 */
00720     } else {
00721         lgw_reg_w(LGW_FSK_MODEM_ENABLE, 0);
00722     }
00723 
00724     /* Load firmware */
00725     reset_firmware(MCU_ARB);
00726     reset_firmware(MCU_AGC);
00727     lgw_reg_w(LGW_MCU_RST_0, 1);
00728     lgw_reg_w(LGW_MCU_RST_1, 1);
00729 
00730     /* gives the AGC MCU control over radio, RF front-end and filter gain */
00731     lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL, 0);
00732     lgw_reg_w(LGW_FORCE_HOST_FE_CTRL, 0);
00733     lgw_reg_w(LGW_FORCE_DEC_FILTER_GAIN, 0);
00734 
00735     /* Get MCUs out of reset */
00736     lgw_reg_w(LGW_RADIO_SELECT, 0); /* MUST not be = to 1 or 2 at firmware init */
00737     lgw_reg_w(LGW_MCU_RST_0, 0);
00738     lgw_reg_w(LGW_MCU_RST_1, 0);
00739 
00740     /* Check firmware version */
00741     lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, FW_VERSION_ADDR);
00742     lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
00743     fw_version = (uint8_t)read_val;
00744     if (fw_version != FW_VERSION_AGC) {
00745         DEBUG_PRINTF("ERROR: Version of AGC firmware not expected, actual:%d expected:%d\n", fw_version, FW_VERSION_AGC);
00746         return LGW_HAL_ERROR;
00747     }
00748     lgw_reg_w(LGW_DBG_ARB_MCU_RAM_ADDR, FW_VERSION_ADDR);
00749     lgw_reg_r(LGW_DBG_ARB_MCU_RAM_DATA, &read_val);
00750     fw_version = (uint8_t)read_val;
00751     if (fw_version != FW_VERSION_ARB) {
00752         DEBUG_PRINTF("ERROR: Version of arbiter firmware not expected, actual:%d expected:%d\n", fw_version, FW_VERSION_ARB);
00753         return LGW_HAL_ERROR;
00754     }
00755 
00756     DEBUG_MSG("Info: Initialising AGC firmware...\n");
00757     wait_us(100); /* Need to wait for long enough here */
00758     lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
00759     if (read_val != 0x10) {
00760         DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS1 0x%02X\n", (uint8_t)read_val);
00761         return LGW_HAL_ERROR;
00762     }
00763 
00764     /* Update Tx gain LUT and start AGC */
00765     for (i = 0; i < txgain_lut.size ; ++i) {
00766         lgw_reg_w(LGW_RADIO_SELECT, AGC_CMD_WAIT); /* start a transaction */
00767         wait_us(DELAYSTART);
00768         load_val = txgain_lut.lut[i].mix_gain  + (16 * txgain_lut.lut[i].dac_gain ) + (64 * txgain_lut.lut[i].pa_gain );
00769         lgw_reg_w(LGW_RADIO_SELECT, load_val);
00770         wait_us(DELAYSTART);
00771         lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
00772         if (read_val != (0x30 + i)) {
00773             DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS2 0x%02X\n", (uint8_t)read_val);
00774             return LGW_HAL_ERROR;
00775         }
00776     }
00777 
00778     /* As the AGC fw is waiting for 16 entries, we need to abort the transaction if we get less entries */
00779     if (txgain_lut.size  < TX_GAIN_LUT_SIZE_MAX) {
00780         lgw_reg_w(LGW_RADIO_SELECT, AGC_CMD_WAIT);
00781         wait_us(DELAYSTART);
00782         load_val = AGC_CMD_ABORT;
00783         lgw_reg_w(LGW_RADIO_SELECT, load_val);
00784         wait_us(DELAYSTART);
00785         lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
00786         if (read_val != 0x30) {
00787             DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS3 0x%02X\n", (uint8_t)read_val);
00788             return LGW_HAL_ERROR;
00789         }
00790     }
00791 
00792     /* Load Tx freq MSBs (always 3 if f > 768 for SX1257 or f > 384 for SX1255 */
00793     lgw_reg_w(LGW_RADIO_SELECT, AGC_CMD_WAIT);
00794     wait_us(DELAYSTART);
00795     lgw_reg_w(LGW_RADIO_SELECT, 3);
00796     wait_us(DELAYSTART);
00797     lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
00798     if (read_val != 0x33) {
00799         DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS4 0x%02X\n", (uint8_t)read_val);
00800         return LGW_HAL_ERROR;
00801     }
00802 
00803     /* Load chan_select firmware option */
00804     lgw_reg_w(LGW_RADIO_SELECT, AGC_CMD_WAIT);
00805     wait_us(DELAYSTART);
00806     lgw_reg_w(LGW_RADIO_SELECT, 0);
00807     wait_us(DELAYSTART);
00808     lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
00809     if (read_val != 0x30) {
00810         DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS5 0x%02X\n", (uint8_t)read_val);
00811         return LGW_HAL_ERROR;
00812     }
00813 
00814     /* End AGC firmware init and check status */
00815     lgw_reg_w(LGW_RADIO_SELECT, AGC_CMD_WAIT);
00816     wait_us(DELAYSTART);
00817     lgw_reg_w(LGW_RADIO_SELECT, radio_select); /* Load intended value of RADIO_SELECT */
00818     wait_us(DELAYSTART);
00819     lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
00820     if (read_val != 0x40) {
00821         DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS 0x%02X\n", (uint8_t)read_val);
00822         return LGW_HAL_ERROR;
00823     }
00824 
00825     /* do not enable GPS event capture */
00826     lgw_reg_w(LGW_GPS_EN, 0);
00827 
00828     /* enable radio for V1 */
00829 #ifndef V2
00830     lgw_reg_w(LGW_RADIO_A_EN, 1);
00831 #endif
00832 
00833     DEBUG_MSG("Info: concentrator restarted...\n");
00834 
00835     return LGW_HAL_SUCCESS;
00836 }
00837 
00838 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00839 
00840 int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) {
00841     int nb_pkt_fetch; /* loop variable and return value */
00842     struct lgw_pkt_rx_s *p; /* pointer to the current structure in the struct array */
00843     uint8_t buff[255 + RX_METADATA_NB]; /* buffer to store the result of SPI read bursts */
00844     unsigned sz; /* size of the payload, uses to address metadata */
00845     int ifmod; /* type of if_chain/modem a packet was received by */
00846     int stat_fifo; /* the packet status as indicated in the FIFO */
00847     uint32_t raw_timestamp; /* timestamp when internal 'RX finished' was triggered */
00848     uint32_t delay_x, delay_y, delay_z; /* temporary variable for timestamp offset calculation */
00849     uint32_t timestamp_correction; /* correction to account for processing delay */
00850     uint32_t sf, cr, bw_pow, crc_en, ppm; /* used to calculate timestamp correction */
00851 
00852     /* check input variables */
00853     if ((max_pkt == 0) || (max_pkt > LGW_PKT_FIFO_SIZE)) {
00854         DEBUG_PRINTF("ERROR: %d = INVALID MAX NUMBER OF PACKETS TO FETCH\n", max_pkt);
00855         return LGW_HAL_ERROR;
00856     }
00857     CHECK_NULL(pkt_data);
00858 
00859     /* Initialize buffer */
00860     memset(buff, 0, sizeof buff);
00861 
00862     /* iterate max_pkt times at most */
00863     for (nb_pkt_fetch = 0; nb_pkt_fetch < max_pkt; ++nb_pkt_fetch) {
00864 
00865         /* point to the proper struct in the struct array */
00866         p = &pkt_data[nb_pkt_fetch];
00867 
00868         /* fetch all the RX FIFO data */
00869         lgw_reg_rb(LGW_RX_PACKET_DATA_FIFO_NUM_STORED, buff, 5);
00870         /* 0:   number of packets available in RX data buffer */
00871         /* 1,2: start address of the current packet in RX data buffer */
00872         /* 3:   CRC status of the current packet */
00873         /* 4:   size of the current packet payload in byte */
00874 
00875         /* how many packets are in the RX buffer ? Break if zero */
00876         if (buff[0] == 0) {
00877             break; /* no more packets to fetch, exit out of FOR loop */
00878         }
00879 
00880         /* sanity check */
00881         if (buff[0] > LGW_PKT_FIFO_SIZE) {
00882             DEBUG_PRINTF("WARNING: %u = INVALID NUMBER OF PACKETS TO FETCH, ABORTING\n", buff[0]);
00883             break;
00884         }
00885 
00886         DEBUG_PRINTF("FIFO content: %x %x %x %x %x\n", buff[0], buff[1], buff[2], buff[3], buff[4]);
00887 
00888         p->size  = buff[4];
00889         sz = p->size ;
00890         stat_fifo = buff[3]; /* will be used later, need to save it before overwriting buff */
00891 
00892         /* get payload + metadata */
00893         lgw_reg_rb(LGW_RX_DATA_BUF_DATA, buff, sz + RX_METADATA_NB);
00894 
00895         /* copy payload to result struct */
00896         memcpy((void *)p->payload , (void *)buff, sz);
00897 
00898         /* process metadata */
00899         p->if_chain  = buff[sz + 0];
00900         if (p->if_chain  >= LGW_IF_CHAIN_NB) {
00901             DEBUG_PRINTF("WARNING: %u NOT A VALID IF_CHAIN NUMBER, ABORTING\n", p->if_chain );
00902             break;
00903         }
00904         ifmod = ifmod_config[p->if_chain ];
00905         DEBUG_PRINTF("[%d %d]\n", p->if_chain , ifmod);
00906 
00907         p->rf_chain  = (uint8_t)if_rf_chain[p->if_chain ];
00908         p->freq_hz = (uint32_t)((int32_t)rf_rx_freq[p->rf_chain ] + if_freq[p->if_chain ]);
00909         p->rssi  = (float)buff[sz + 5] + rf_rssi_offset[p->rf_chain ];
00910 
00911         if ((ifmod == IF_LORA_MULTI) || (ifmod == IF_LORA_STD)) {
00912             DEBUG_MSG("Note: LoRa packet\n");
00913             switch (stat_fifo & 0x07) {
00914                 case 5:
00915                     p->status  = STAT_CRC_OK;
00916                     crc_en = 1;
00917                     break;
00918                 case 7:
00919                     p->status  = STAT_CRC_BAD;
00920                     crc_en = 1;
00921                     break;
00922                 case 1:
00923                     p->status  = STAT_NO_CRC;
00924                     crc_en = 0;
00925                     break;
00926                 default:
00927                     p->status  = STAT_UNDEFINED;
00928                     crc_en = 0;
00929             }
00930             p->modulation  = MOD_LORA;
00931             p->snr  = ((float)((int8_t)buff[sz + 2])) / 4;
00932             p->snr_min  = ((float)((int8_t)buff[sz + 3])) / 4;
00933             p->snr_max  = ((float)((int8_t)buff[sz + 4])) / 4;
00934             if (ifmod == IF_LORA_MULTI) {
00935                 p->bandwidth  = BW_125KHZ; /* fixed in hardware */
00936             } else {
00937                 p->bandwidth  = lora_rx_bw; /* get the parameter from the config variable */
00938             }
00939             sf = (buff[sz + 1] >> 4) & 0x0F;
00940 
00941             switch (sf) {
00942                 case 7:
00943                     p->datarate  = DR_LORA_SF7;
00944                     break;
00945                 case 8:
00946                     p->datarate  = DR_LORA_SF8;
00947                     break;
00948                 case 9:
00949                     p->datarate  = DR_LORA_SF9;
00950                     break;
00951                 case 10:
00952                     p->datarate  = DR_LORA_SF10;
00953                     break;
00954                 case 11:
00955                     p->datarate  = DR_LORA_SF11;
00956                     break;
00957                 case 12:
00958                     p->datarate  = DR_LORA_SF12;
00959                     break;
00960                 default:
00961                     p->datarate  = DR_UNDEFINED;
00962             }
00963             cr = (buff[sz + 1] >> 1) & 0x07;
00964             switch (cr) {
00965                 case 1:
00966                     p->coderate  = CR_LORA_4_5;
00967                     break;
00968                 case 2:
00969                     p->coderate  = CR_LORA_4_6;
00970                     break;
00971                 case 3:
00972                     p->coderate  = CR_LORA_4_7;
00973                     break;
00974                 case 4:
00975                     p->coderate  = CR_LORA_4_8;
00976                     break;
00977                 default:
00978                     p->coderate  = CR_UNDEFINED;
00979             }
00980 
00981             /* determine if 'PPM mode' is on, needed for timestamp correction */
00982             if (SET_PPM_ON(p->bandwidth , p->datarate )) {
00983                 ppm = 1;
00984             } else {
00985                 ppm = 0;
00986             }
00987 
00988             /* timestamp correction code, base delay */
00989             if (ifmod == IF_LORA_STD) { /* if packet was received on the stand-alone LoRa modem */
00990                 switch (lora_rx_bw) {
00991                     case BW_125KHZ:
00992                         delay_x = 64;
00993                         bw_pow = 1;
00994                         break;
00995                     case BW_250KHZ:
00996                         delay_x = 32;
00997                         bw_pow = 2;
00998                         break;
00999                     case BW_500KHZ:
01000                         delay_x = 16;
01001                         bw_pow = 4;
01002                         break;
01003                     default:
01004                         DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", p->bandwidth );
01005                         delay_x = 0;
01006                         bw_pow = 0;
01007                 }
01008             } else { /* packet was received on one of the sensor channels = 125kHz */
01009                 delay_x = 114;
01010                 bw_pow = 1;
01011             }
01012 
01013             /* timestamp correction code, variable delay */
01014             if ((sf >= 6) && (sf <= 12) && (bw_pow > 0)) {
01015                 if ((2 * (sz + 2 * crc_en) - (sf - 7)) <= 0) { /* payload fits entirely in first 8 symbols */
01016                     delay_y = (((1 << (sf - 1)) * (sf + 1)) + (3 * (1 << (sf - 4)))) / bw_pow;
01017                     delay_z = 32 * (2 * (sz + 2 * crc_en) + 5) / bw_pow;
01018                 } else {
01019                     delay_y = (((1 << (sf - 1)) * (sf + 1)) + ((4 - ppm) * (1 << (sf - 4)))) / bw_pow;
01020                     delay_z = (16 + 4 * cr) * (((2 * (sz + 2 * crc_en) - sf + 6) % (sf - 2 * ppm)) + 1) / bw_pow;
01021                 }
01022                 timestamp_correction = delay_x + delay_y + delay_z;
01023             } else {
01024                 timestamp_correction = 0;
01025                 DEBUG_MSG("WARNING: invalid packet, no timestamp correction\n");
01026             }
01027 
01028             /* RSSI correction */
01029             if (ifmod == IF_LORA_MULTI) {
01030                 p->rssi  -= RSSI_MULTI_BIAS;
01031             }
01032 
01033         } else if (ifmod == IF_FSK_STD) {
01034             DEBUG_MSG("Note: FSK packet\n");
01035             switch (stat_fifo & 0x07) {
01036                 case 5:
01037                     p->status  = STAT_CRC_OK;
01038                     break;
01039                 case 7:
01040                     p->status  = STAT_CRC_BAD;
01041                     break;
01042                 case 1:
01043                     p->status  = STAT_NO_CRC;
01044                     break;
01045                 default:
01046                     p->status  = STAT_UNDEFINED;
01047                     break;
01048             }
01049             p->modulation  = MOD_FSK;
01050             p->snr  = -128.0;
01051             p->snr_min  = -128.0;
01052             p->snr_max  = -128.0;
01053             p->bandwidth  = fsk_rx_bw;
01054             p->datarate  = fsk_rx_dr;
01055             p->coderate  = CR_UNDEFINED;
01056             timestamp_correction = ((uint32_t)680000 / fsk_rx_dr) - 20;
01057 
01058             /* RSSI correction */
01059             p->rssi  = (RSSI_FSK_POLY_0) + ((float)(RSSI_FSK_POLY_1) * p->rssi ) + ((float)(RSSI_FSK_POLY_2) * (p->rssi ) * (p->rssi ));
01060         } else {
01061             DEBUG_MSG("ERROR: UNEXPECTED PACKET ORIGIN\n");
01062             p->status  = STAT_UNDEFINED;
01063             p->modulation  = MOD_UNDEFINED;
01064             p->rssi  = -128.0;
01065             p->snr  = -128.0;
01066             p->snr_min  = -128.0;
01067             p->snr_max  = -128.0;
01068             p->bandwidth  = BW_UNDEFINED;
01069             p->datarate  = DR_UNDEFINED;
01070             p->coderate  = CR_UNDEFINED;
01071             timestamp_correction = 0;
01072         }
01073 
01074         raw_timestamp = (uint32_t)buff[sz + 6] + ((uint32_t)buff[sz + 7] << 8) + ((uint32_t)buff[sz + 8] << 16) + ((uint32_t)buff[sz + 9] << 24);
01075         p->count_us  = raw_timestamp - timestamp_correction + Sx1308.offtmstpstm32; /* corrected with PicoCell offset */
01076         p->crc  = (uint16_t)buff[sz + 10] + ((uint16_t)buff[sz + 11] << 8);
01077 
01078         /* advance packet FIFO */
01079         lgw_reg_w(LGW_RX_PACKET_DATA_FIFO_NUM_STORED, 0);
01080     }
01081 
01082     return nb_pkt_fetch;
01083 }
01084 
01085 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
01086 
01087 int lgw_send(struct lgw_pkt_tx_s pkt_data) {
01088     int i;
01089     uint8_t buff[256 + TX_METADATA_NB]; /* buffer to prepare the packet to send + metadata before SPI write burst */
01090     uint32_t part_int = 0; /* integer part for PLL register value calculation */
01091     uint32_t part_frac = 0; /* fractional part for PLL register value calculation */
01092     uint16_t fsk_dr_div; /* divider to configure for target datarate */
01093     int transfer_size = 0; /* data to transfer from host to TX databuffer */
01094     int payload_offset = 0; /* start of the payload content in the databuffer */
01095     uint8_t pow_index = 0; /* 4-bit value to set the firmware TX power */
01096     uint8_t target_mix_gain = 0; /* used to select the proper I/Q offset correction */
01097     uint32_t count_trig = 0; /* timestamp value in trigger mode corrected for TX start delay */
01098 
01099     /* check input range (segfault prevention) */
01100     if (pkt_data.rf_chain  >= LGW_RF_CHAIN_NB) {
01101         DEBUG_MSG("ERROR: INVALID RF_CHAIN TO SEND PACKETS\n");
01102         return LGW_HAL_ERROR;
01103     }
01104 
01105     /* check input variables */
01106     if (rf_tx_enable[pkt_data.rf_chain ] == false) {
01107         DEBUG_MSG("ERROR: SELECTED RF_CHAIN IS DISABLED FOR TX ON SELECTED BOARD\n");
01108         return LGW_HAL_ERROR;
01109     }
01110     if (rf_enable[pkt_data.rf_chain ] == false) {
01111         DEBUG_MSG("ERROR: SELECTED RF_CHAIN IS DISABLED\n");
01112         return LGW_HAL_ERROR;
01113     }
01114     if (!IS_TX_MODE(pkt_data.tx_mode )) {
01115         DEBUG_MSG("ERROR: TX_MODE NOT SUPPORTED\n");
01116         return LGW_HAL_ERROR;
01117     }
01118     if (pkt_data.modulation  == MOD_LORA) {
01119         if (!IS_LORA_BW(pkt_data.bandwidth )) {
01120             DEBUG_MSG("ERROR: BANDWIDTH NOT SUPPORTED BY LORA TX\n");
01121             return LGW_HAL_ERROR;
01122         }
01123         if (!IS_LORA_STD_DR(pkt_data.datarate )) {
01124             DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY LORA TX\n");
01125             return LGW_HAL_ERROR;
01126         }
01127         if (!IS_LORA_CR(pkt_data.coderate )) {
01128             DEBUG_MSG("ERROR: CODERATE NOT SUPPORTED BY LORA TX\n");
01129             return LGW_HAL_ERROR;
01130         }
01131         if (pkt_data.size  > 255) {
01132             DEBUG_MSG("ERROR: PAYLOAD LENGTH TOO BIG FOR LORA TX\n");
01133             return LGW_HAL_ERROR;
01134         }
01135     } else if (pkt_data.modulation  == MOD_FSK) {
01136         if ((pkt_data.f_dev  < 1) || (pkt_data.f_dev  > 200)) {
01137             DEBUG_MSG("ERROR: TX FREQUENCY DEVIATION OUT OF ACCEPTABLE RANGE\n");
01138             return LGW_HAL_ERROR;
01139         }
01140         if (!IS_FSK_DR(pkt_data.datarate )) {
01141             DEBUG_MSG("ERROR: DATARATE NOT SUPPORTED BY FSK IF CHAIN\n");
01142             return LGW_HAL_ERROR;
01143         }
01144         if (pkt_data.size  > 255) {
01145             DEBUG_MSG("ERROR: PAYLOAD LENGTH TOO BIG FOR FSK TX\n");
01146             return LGW_HAL_ERROR;
01147         }
01148     } else {
01149         DEBUG_MSG("ERROR: INVALID TX MODULATION\n");
01150         return LGW_HAL_ERROR;
01151     }
01152 
01153     /* interpretation of TX power */
01154     for (pow_index = txgain_lut.size  - 1; pow_index > 0; pow_index--) {
01155         if (txgain_lut.lut[pow_index].rf_power  <= pkt_data.rf_power ) {
01156             break;
01157         }
01158     }
01159 
01160     /* Save radio calibration for next restart */
01161     calibration_save();
01162     
01163     /* loading TX imbalance correction */
01164     target_mix_gain = txgain_lut.lut[pow_index].mix_gain ;
01165     if (pkt_data.rf_chain  == 0) { /* use radio A calibration table */
01166         lgw_reg_w(LGW_TX_OFFSET_I, cal_offset_a_i[target_mix_gain ]);
01167         lgw_reg_w(LGW_TX_OFFSET_Q, cal_offset_a_q[target_mix_gain ]);
01168     } else { /* use radio B calibration table */
01169         lgw_reg_w(LGW_TX_OFFSET_I, cal_offset_b_i[target_mix_gain ]);
01170         lgw_reg_w(LGW_TX_OFFSET_Q, cal_offset_b_q[target_mix_gain ]);
01171     }
01172 
01173     /* Set digital gain from LUT */
01174     lgw_reg_w(LGW_TX_GAIN, txgain_lut.lut[pow_index].dig_gain);
01175 
01176     /* fixed metadata, useful payload and misc metadata compositing */
01177     transfer_size = TX_METADATA_NB + pkt_data.size ; /*  */
01178     payload_offset = TX_METADATA_NB; /* start the payload just after the metadata */
01179 
01180     /* metadata 0 to 2, TX PLL frequency */
01181     switch (rf_radio_type[0]) { /* we assume that there is only one radio type on the board */
01182         case LGW_RADIO_TYPE_SX1255:
01183             part_int = pkt_data.freq_hz / (SX125x_32MHz_FRAC << 7); /* integer part, gives the MSB */
01184             part_frac = ((pkt_data.freq_hz % (SX125x_32MHz_FRAC << 7)) << 9) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */
01185             break;
01186         case LGW_RADIO_TYPE_SX1257:
01187             part_int = pkt_data.freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */
01188             part_frac = ((pkt_data.freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */
01189             break;
01190         default:
01191             DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d FOR RADIO TYPE\n", rf_radio_type[0]);
01192             break;
01193     }
01194 
01195     buff[0] = 0xFF & part_int; /* Most Significant Byte */
01196     buff[1] = 0xFF & (part_frac >> 8); /* middle byte */
01197     buff[2] = 0xFF & part_frac; /* Least Significant Byte */
01198 
01199     /* metadata 3 to 6, timestamp trigger value */
01200     /* TX state machine must be triggered at T0 - TX_START_DELAY for packet to start being emitted at T0 */
01201     if (pkt_data.tx_mode  == TIMESTAMPED) {
01202         count_trig = pkt_data.count_us  - TX_START_DELAY - Sx1308.offtmstpstm32; /* Corrected with PicoCell offset */
01203         buff[3] = 0xFF & (count_trig >> 24);
01204         buff[4] = 0xFF & (count_trig >> 16);
01205         buff[5] = 0xFF & (count_trig >> 8);
01206         buff[6] = 0xFF & count_trig;
01207     }
01208 
01209     /* parameters depending on modulation  */
01210     if (pkt_data.modulation  == MOD_LORA) {
01211         /* metadata 7, modulation type, radio chain selection and TX power */
01212         buff[7] = (0x20 & (pkt_data.rf_chain  << 5)) | (0x0F & pow_index); /* bit 4 is 0 -> LoRa modulation */
01213 
01214         buff[8] = 0; /* metadata 8, not used */
01215 
01216         /* metadata 9, CRC, LoRa CR & SF */
01217         switch (pkt_data.datarate ) {
01218             case DR_LORA_SF7:
01219                 buff[9] = 7;
01220                 break;
01221             case DR_LORA_SF8:
01222                 buff[9] = 8;
01223                 break;
01224             case DR_LORA_SF9:
01225                 buff[9] = 9;
01226                 break;
01227             case DR_LORA_SF10:
01228                 buff[9] = 10;
01229                 break;
01230             case DR_LORA_SF11:
01231                 buff[9] = 11;
01232                 break;
01233             case DR_LORA_SF12:
01234                 buff[9] = 12;
01235                 break;
01236             default:
01237                 DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.datarate );
01238         }
01239         switch (pkt_data.coderate ) {
01240             case CR_LORA_4_5:
01241                 buff[9] |= 1 << 4;
01242                 break;
01243             case CR_LORA_4_6:
01244                 buff[9] |= 2 << 4;
01245                 break;
01246             case CR_LORA_4_7:
01247                 buff[9] |= 3 << 4;
01248                 break;
01249             case CR_LORA_4_8:
01250                 buff[9] |= 4 << 4;
01251                 break;
01252             default:
01253                 DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.coderate );
01254         }
01255         if (pkt_data.no_crc  == false) {
01256             buff[9] |= 0x80; /* set 'CRC enable' bit */
01257         } else {
01258             DEBUG_MSG("Info: packet will be sent without CRC\n");
01259         }
01260 
01261         /* metadata 10, payload size */
01262         buff[10] = pkt_data.size ;
01263 
01264         /* metadata 11, implicit header, modulation bandwidth, PPM offset & polarity */
01265         switch (pkt_data.bandwidth ) {
01266             case BW_125KHZ:
01267                 buff[11] = 0;
01268                 break;
01269             case BW_250KHZ:
01270                 buff[11] = 1;
01271                 break;
01272             case BW_500KHZ:
01273                 buff[11] = 2;
01274                 break;
01275             default:
01276                 DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.bandwidth );
01277         }
01278         if (pkt_data.no_header  == true) {
01279             buff[11] |= 0x04; /* set 'implicit header' bit */
01280         }
01281         if (SET_PPM_ON(pkt_data.bandwidth , pkt_data.datarate )) {
01282             buff[11] |= 0x08; /* set 'PPM offset' bit at 1 */
01283         }
01284         if (pkt_data.invert_pol  == true) {
01285             buff[11] |= 0x10; /* set 'TX polarity' bit at 1 */
01286         }
01287 
01288         /* metadata 12 & 13, LoRa preamble size */
01289         if (pkt_data.preamble  == 0) { /* if not explicit, use recommended LoRa preamble size */
01290             pkt_data.preamble  = STD_LORA_PREAMBLE;
01291         } else if (pkt_data.preamble  < MIN_LORA_PREAMBLE) { /* enforce minimum preamble size */
01292             pkt_data.preamble  = MIN_LORA_PREAMBLE;
01293             DEBUG_MSG("Note: preamble length adjusted to respect minimum LoRa preamble size\n");
01294         }
01295         buff[12] = 0xFF & (pkt_data.preamble  >> 8);
01296         buff[13] = 0xFF & pkt_data.preamble ;
01297 
01298         /* metadata 14 & 15, not used */
01299         buff[14] = 0;
01300         buff[15] = 0;
01301 
01302         /* MSB of RF frequency is now used in AGC firmware to implement large/narrow filtering in SX1257/55 */
01303         buff[0] &= 0x3F; /* Unset 2 MSBs of frequency code */
01304         if (pkt_data.bandwidth  == BW_500KHZ) {
01305             buff[0] |= 0x80; /* Set MSB bit to enlarge analog filter for 500kHz BW */
01306         } else if (pkt_data.bandwidth  == BW_125KHZ) {
01307             buff[0] |= 0x40; /* Set MSB-1 bit to enable digital filter for 125kHz BW */
01308         }
01309 
01310     } else if (pkt_data.modulation  == MOD_FSK) {
01311         /* metadata 7, modulation type, radio chain selection and TX power */
01312         buff[7] = (0x20 & (pkt_data.rf_chain  << 5)) | 0x10 | (0x0F & pow_index); /* bit 4 is 1 -> FSK modulation */
01313 
01314         buff[8] = 0; /* metadata 8, not used */
01315 
01316         /* metadata 9, frequency deviation */
01317         buff[9] = pkt_data.f_dev ;
01318 
01319         /* metadata 10, payload size */
01320         buff[10] = pkt_data.size ;
01321         /* TODO: how to handle 255 bytes packets ?!? */
01322 
01323         /* metadata 11, packet mode, CRC, encoding */
01324         buff[11] = 0x01 | (pkt_data.no_crc  ? 0 : 0x02) | (0x02 << 2); /* always in variable length packet mode, whitening, and CCITT CRC if CRC is not disabled  */
01325 
01326         /* metadata 12 & 13, FSK preamble size */
01327         if (pkt_data.preamble  == 0) { /* if not explicit, use LoRa MAC preamble size */
01328             pkt_data.preamble  = STD_FSK_PREAMBLE;
01329         } else if (pkt_data.preamble  < MIN_FSK_PREAMBLE) { /* enforce minimum preamble size */
01330             pkt_data.preamble  = MIN_FSK_PREAMBLE;
01331             DEBUG_MSG("Note: preamble length adjusted to respect minimum FSK preamble size\n");
01332         }
01333         buff[12] = 0xFF & (pkt_data.preamble  >> 8);
01334         buff[13] = 0xFF & pkt_data.preamble ;
01335 
01336         /* metadata 14 & 15, FSK baudrate */
01337         fsk_dr_div = (uint16_t)((uint32_t)LGW_XTAL_FREQU / pkt_data.datarate ); /* Ok for datarate between 500bps and 250kbps */
01338         buff[14] = 0xFF & (fsk_dr_div >> 8);
01339         buff[15] = 0xFF & fsk_dr_div;
01340 
01341         /* insert payload size in the packet for variable mode */
01342         buff[16] = pkt_data.size ;
01343         ++transfer_size; /* one more byte to transfer to the TX modem */
01344         ++payload_offset; /* start the payload with one more byte of offset */
01345 
01346         /* MSB of RF frequency is now used in AGC firmware to implement large/narrow filtering in SX1257/55 */
01347         buff[0] &= 0x7F; /* Always use narrow band for FSK (force MSB to 0) */
01348 
01349     } else {
01350         DEBUG_MSG("ERROR: INVALID TX MODULATION..\n");
01351         return LGW_HAL_ERROR;
01352     }
01353 
01354     /* copy payload from user struct to buffer containing metadata */
01355     memcpy((void *)(buff + payload_offset), (void *)(pkt_data.payload ), pkt_data.size );
01356 
01357     /* reset TX command flags */
01358     lgw_abort_tx();
01359 
01360     /* put metadata + payload in the TX data buffer */
01361     lgw_reg_w(LGW_TX_DATA_BUF_ADDR, 0);
01362     lgw_reg_wb(LGW_TX_DATA_BUF_DATA, buff, transfer_size);
01363     DEBUG_ARRAY(i, transfer_size, buff);
01364 
01365     switch (pkt_data.tx_mode ) {
01366         case IMMEDIATE:
01367             lgw_reg_w(LGW_TX_TRIG_IMMEDIATE, 1);
01368             break;
01369 
01370         case TIMESTAMPED:
01371             lgw_reg_w(LGW_TX_TRIG_DELAYED, 1);
01372             break;
01373 
01374         case ON_GPS:
01375             lgw_reg_w(LGW_TX_TRIG_GPS, 1);
01376             break;
01377 
01378         default:
01379             DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.tx_mode );
01380             return LGW_HAL_ERROR;
01381     }
01382 
01383     DEBUG_MSG("Note: lgw_send() done.\n");
01384 
01385     return LGW_HAL_SUCCESS;
01386 }
01387 
01388 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
01389 
01390 int lgw_status(uint8_t select, uint8_t *code) {
01391     int32_t read_value;
01392 
01393     /* check input variables */
01394     CHECK_NULL(code);
01395 
01396     if (select == TX_STATUS) {
01397         lgw_reg_r(LGW_TX_STATUS, &read_value);
01398         if ((read_value & 0x10) == 0) { /* bit 4 @1: TX programmed */
01399             *code = TX_FREE;
01400         } else if ((read_value & 0x60) != 0) { /* bit 5 or 6 @1: TX sequence */
01401             *code = TX_EMITTING;
01402         } else {
01403             *code = TX_SCHEDULED;
01404         }
01405         return LGW_HAL_SUCCESS;
01406 
01407     } else if (select == RX_STATUS) {
01408         *code = RX_STATUS_UNKNOWN; /* todo */
01409         return LGW_HAL_SUCCESS;
01410 
01411     } else {
01412         DEBUG_MSG("ERROR: SELECTION INVALID, NO STATUS TO RETURN\n");
01413         return LGW_HAL_ERROR;
01414     }
01415 
01416 }
01417 
01418 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
01419 
01420 int lgw_abort_tx(void) {
01421     int i;
01422 
01423     i = lgw_reg_w(LGW_TX_TRIG_ALL, 0);
01424 
01425     if (i == LGW_REG_SUCCESS) {
01426         return LGW_HAL_SUCCESS;
01427     } else {
01428         return LGW_HAL_ERROR;
01429     }
01430 }
01431 
01432 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
01433 
01434 int lgw_get_trigcnt(uint32_t* trig_cnt_us) {
01435     int i;
01436     int32_t val;
01437 
01438     i = lgw_reg_r(LGW_TIMESTAMP, &val);
01439     if (i == LGW_REG_SUCCESS) {
01440         *trig_cnt_us = (uint32_t)val;
01441         return LGW_HAL_SUCCESS;
01442     } else {
01443         return LGW_HAL_ERROR;
01444     }
01445 }
01446 
01447 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
01448 
01449 const char* lgw_version_info() {
01450     return lgw_version_string;
01451 }
01452 
01453 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
01454 
01455 uint32_t lgw_time_on_air(struct lgw_pkt_tx_s *packet) {
01456     int32_t val;
01457     uint8_t SF, H, DE;
01458     uint16_t BW;
01459     uint32_t payloadSymbNb, Tpacket;
01460     double Tsym, Tpreamble, Tpayload, Tfsk;
01461 
01462     if (packet == NULL) {
01463         DEBUG_MSG("ERROR: Failed to compute time on air, wrong parameter\n");
01464         return 0;
01465     }
01466 
01467     if (packet->modulation  == MOD_LORA) {
01468         /* Get bandwidth */
01469         val = lgw_bw_getval(packet->bandwidth );
01470         if (val != -1) {
01471             BW = (uint16_t)(val / 1E3);
01472         } else {
01473             DEBUG_PRINTF("ERROR: Cannot compute time on air for this packet, unsupported bandwidth (0x%02X)\n", packet->bandwidth );
01474             return 0;
01475         }
01476 
01477         /* Get datarate */
01478         val = lgw_sf_getval(packet->datarate );
01479         if (val != -1) {
01480             SF = (uint8_t)val;
01481         } else {
01482             DEBUG_PRINTF("ERROR: Cannot compute time on air for this packet, unsupported datarate (0x%02X)\n", packet->datarate );
01483             return 0;
01484         }
01485 
01486         /* Duration of 1 symbol */
01487         Tsym = (2 ^ SF) / BW;
01488 
01489         /* Duration of preamble */
01490         Tpreamble = (8 + 4.25) * Tsym; /* 8 programmed symbols in preamble */
01491 
01492         /* Duration of payload */
01493         H = (packet->no_header  == false) ? 0 : 1; /* header is always enabled, except for beacons */
01494         DE = (SF >= 11) ? 1 : 0; /* Low datarate optimization enabled for SF11 and SF12 */
01495 
01496         payloadSymbNb = 8 + (ceil((double)(8 * packet->size  - 4 * SF + 28 + 16 - 20 * H) / (double)(4 * (SF - 2 * DE))) * (packet->coderate  + 4)); /* Explicitely cast to double to keep precision of the division */
01497 
01498         Tpayload = payloadSymbNb * Tsym;
01499 
01500         /* Duration of packet */
01501         Tpacket = Tpreamble + Tpayload;
01502     } else if (packet->modulation  == MOD_FSK) {
01503         /* PREAMBLE + SYNC_WORD + PKT_LEN + PKT_PAYLOAD + CRC
01504         PREAMBLE: default 5 bytes
01505         SYNC_WORD: default 3 bytes
01506         PKT_LEN: 1 byte (variable length mode)
01507         PKT_PAYLOAD: x bytes
01508         CRC: 0 or 2 bytes
01509         */
01510         Tfsk = (8 * (double)(packet->preamble  + fsk_sync_word_size + 1 + packet->size  + ((packet->no_crc  == true) ? 0 : 2)) / (double)packet->datarate ) * 1E3;
01511 
01512         /* Duration of packet */
01513         Tpacket = (uint32_t)Tfsk + 1; /* add margin for rounding */
01514     } else {
01515         Tpacket = 0;
01516         DEBUG_PRINTF("ERROR: Cannot compute time on air for this packet, unsupported modulation (0x%02X)\n", packet->modulation );
01517     }
01518 
01519     return Tpacket;
01520 }
01521 
01522 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
01523 
01524 void lgw_calibration_offset_transfer(uint8_t idx_start, uint8_t idx_nb) {
01525     int i;
01526     int read_val;
01527 
01528     DEBUG_PRINTF("start calibration for index [%u-%u]\n", idx_start, idx_start + idx_nb);
01529 
01530     /* Get 'idx_nb' calibration offsets from AGC FW, and put it in the local 
01531     calibration offsets array, at 'idx_start' index position */
01532     for(i = 0; i < idx_nb; ++i) {
01533         lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xA0 + i);
01534         wait_ms(1);
01535         lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
01536         wait_ms(1);
01537         cal_offset_a_i[i + idx_start] = (int8_t)read_val;
01538         lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xA8 + i);
01539         wait_ms(1);
01540         lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
01541         wait_ms(1);
01542         cal_offset_a_q[i + idx_start] = (int8_t)read_val;
01543         lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xB0 + i);
01544         wait_ms(1);
01545         lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
01546         wait_ms(1);
01547         cal_offset_b_i[i + idx_start] = (int8_t)read_val;
01548         lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xB8 + i);
01549         wait_ms(1);
01550         lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
01551         wait_ms(1);
01552         cal_offset_b_q[i + idx_start] = (int8_t)read_val;
01553     }
01554 
01555     /* Fill the first 5 offsets [0-4] with the value of index 5 */
01556     for(i = 0; i < 5; i++) {
01557         cal_offset_a_i[i] = cal_offset_a_i[5];
01558         cal_offset_a_q[i] = cal_offset_a_q[5];
01559         cal_offset_b_i[i] = cal_offset_b_i[5];
01560         cal_offset_b_q[i] = cal_offset_b_q[5];
01561     }
01562 }
01563 
01564 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
01565 
01566 void calibration_save(void) {
01567     lgw_reg_r(LGW_IQ_MISMATCH_A_AMP_COEFF, &iqrxtab[0]);
01568     lgw_reg_r(LGW_IQ_MISMATCH_A_PHI_COEFF, &iqrxtab[1]);
01569     lgw_reg_r(LGW_IQ_MISMATCH_B_AMP_COEFF, &iqrxtab[2]);
01570     lgw_reg_r(LGW_IQ_MISMATCH_B_PHI_COEFF, &iqrxtab[3]);
01571 }
01572 
01573 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
01574 
01575 void calibration_reload(void) {
01576     lgw_reg_w(LGW_IQ_MISMATCH_A_AMP_COEFF, iqrxtab[0]);
01577     lgw_reg_w(LGW_IQ_MISMATCH_A_PHI_COEFF, iqrxtab[1]);
01578     lgw_reg_w(LGW_IQ_MISMATCH_B_AMP_COEFF, iqrxtab[2]);
01579     lgw_reg_w(LGW_IQ_MISMATCH_B_PHI_COEFF, iqrxtab[3]);
01580 }
01581 
01582 /* --- EOF ------------------------------------------------------------------ */