Driver for SX1272 connected to Pulga devices using only DIO0 pins and polling (error states and timeout).

Dependents:   pulga-mbed-lorawan-gps mbed-lorawan-pulga mbed-lorawan-pulga-testing-channel mbed-lorawan-pulga-serial_rx ... more

Committer:
brunnobbco
Date:
Tue Mar 30 20:08:17 2021 +0000
Revision:
5:3da1a3924c65
Parent:
4:2235ad0a46be
Forget to change another gpio occurrence.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
brunnobbco 0:561d07a737bc 1 /**
brunnobbco 0:561d07a737bc 2 / _____) _ | |
brunnobbco 0:561d07a737bc 3 ( (____ _____ ____ _| |_ _____ ____| |__
brunnobbco 0:561d07a737bc 4 \____ \| ___ | (_ _) ___ |/ ___) _ \
brunnobbco 0:561d07a737bc 5 _____) ) ____| | | || |_| ____( (___| | | |
brunnobbco 0:561d07a737bc 6 (______/|_____)_|_|_| \__)_____)\____)_| |_|
brunnobbco 0:561d07a737bc 7 (C)2013 Semtech
brunnobbco 0:561d07a737bc 8 ___ _____ _ ___ _ _____ ___ ___ ___ ___
brunnobbco 0:561d07a737bc 9 / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
brunnobbco 0:561d07a737bc 10 \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
brunnobbco 0:561d07a737bc 11 |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
brunnobbco 0:561d07a737bc 12 embedded.connectivity.solutions===============
brunnobbco 0:561d07a737bc 13
brunnobbco 0:561d07a737bc 14 Description: Radio driver for Semtech SX1272 LoRa radio chip. Implements LoRaRadio class.
brunnobbco 0:561d07a737bc 15
brunnobbco 0:561d07a737bc 16 License: Revised BSD License, see LICENSE.TXT file include in the project
brunnobbco 0:561d07a737bc 17
brunnobbco 0:561d07a737bc 18 Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
brunnobbco 0:561d07a737bc 19
brunnobbco 0:561d07a737bc 20
brunnobbco 0:561d07a737bc 21 Copyright (c) 2017, Arm Limited and affiliates.
brunnobbco 0:561d07a737bc 22
brunnobbco 0:561d07a737bc 23 SPDX-License-Identifier: BSD-3-Clause
brunnobbco 0:561d07a737bc 24 */
brunnobbco 0:561d07a737bc 25
brunnobbco 0:561d07a737bc 26 #include <stdio.h>
brunnobbco 0:561d07a737bc 27 #include <math.h> //rint
brunnobbco 0:561d07a737bc 28 #include <string.h>
brunnobbco 0:561d07a737bc 29 #include "mbed.h"
brunnobbco 0:561d07a737bc 30
brunnobbco 0:561d07a737bc 31 #include "SX1272_LoRaRadio.h"
brunnobbco 0:561d07a737bc 32 #include "sx1272Regs-Fsk.h"
brunnobbco 0:561d07a737bc 33 #include "sx1272Regs-LoRa.h"
brunnobbco 0:561d07a737bc 34
brunnobbco 0:561d07a737bc 35 #ifdef MBED_SX1272_LORA_RADIO_SPI_FREQUENCY
brunnobbco 0:561d07a737bc 36 #define SPI_FREQUENCY MBED_SX1272_LORA_RADIO_SPI_FREQUENCY
brunnobbco 0:561d07a737bc 37 #else
brunnobbco 0:561d07a737bc 38 #define SPI_FREQUENCY 8000000
brunnobbco 0:561d07a737bc 39 #endif
brunnobbco 0:561d07a737bc 40
brunnobbco 0:561d07a737bc 41 // Sync word for Private LoRa networks
brunnobbco 0:561d07a737bc 42 #define LORA_MAC_PRIVATE_SYNCWORD 0x12
brunnobbco 0:561d07a737bc 43 // Sync word for Public LoRa networks
brunnobbco 0:561d07a737bc 44 #define LORA_MAC_PUBLIC_SYNCWORD 0x34
brunnobbco 0:561d07a737bc 45
brunnobbco 0:561d07a737bc 46 // SX1272 definitions
brunnobbco 0:561d07a737bc 47 #define XTAL_FREQ 32000000
brunnobbco 0:561d07a737bc 48 #define FREQ_STEP 61.03515625
brunnobbco 0:561d07a737bc 49
brunnobbco 0:561d07a737bc 50 enum RadioVariant {
brunnobbco 0:561d07a737bc 51 SX1272UNDEFINED = 0,
brunnobbco 3:bca9a8ee555d 52 SX1272PABOOST = 1,
brunnobbco 3:bca9a8ee555d 53 SX1272NOPABOOST = 2,
brunnobbco 0:561d07a737bc 54 };
brunnobbco 0:561d07a737bc 55
brunnobbco 0:561d07a737bc 56 /*!
brunnobbco 0:561d07a737bc 57 * FSK bandwidth definition
brunnobbco 0:561d07a737bc 58 */
brunnobbco 0:561d07a737bc 59 typedef struct
brunnobbco 0:561d07a737bc 60 {
brunnobbco 0:561d07a737bc 61 uint32_t bandwidth;
brunnobbco 0:561d07a737bc 62 uint8_t register_value;
brunnobbco 0:561d07a737bc 63 } fsk_bw_t;
brunnobbco 0:561d07a737bc 64
brunnobbco 0:561d07a737bc 65 /*!
brunnobbco 0:561d07a737bc 66 * Radio registers definition
brunnobbco 0:561d07a737bc 67 */
brunnobbco 0:561d07a737bc 68 typedef struct
brunnobbco 0:561d07a737bc 69 {
brunnobbco 0:561d07a737bc 70 modem_type modem;
brunnobbco 0:561d07a737bc 71 uint8_t addr;
brunnobbco 0:561d07a737bc 72 uint8_t value;
brunnobbco 0:561d07a737bc 73 } radio_registers_t;
brunnobbco 0:561d07a737bc 74
brunnobbco 0:561d07a737bc 75 /*!
brunnobbco 0:561d07a737bc 76 * Constant values need to compute the RSSI value
brunnobbco 0:561d07a737bc 77 */
brunnobbco 0:561d07a737bc 78 #define RSSI_OFFSET -139
brunnobbco 0:561d07a737bc 79
brunnobbco 0:561d07a737bc 80 #define RADIO_INIT_REGISTERS_VALUE \
brunnobbco 0:561d07a737bc 81 { \
brunnobbco 0:561d07a737bc 82 { MODEM_FSK , REG_LNA , 0x23 },\
brunnobbco 0:561d07a737bc 83 { MODEM_FSK , REG_RXCONFIG , 0x1E },\
brunnobbco 0:561d07a737bc 84 { MODEM_FSK , REG_RSSICONFIG , 0xD2 },\
brunnobbco 0:561d07a737bc 85 { MODEM_FSK , REG_AFCFEI , 0x01 },\
brunnobbco 0:561d07a737bc 86 { MODEM_FSK , REG_PREAMBLEDETECT , 0xAA },\
brunnobbco 0:561d07a737bc 87 { MODEM_FSK , REG_OSC , 0x07 },\
brunnobbco 0:561d07a737bc 88 { MODEM_FSK , REG_SYNCCONFIG , 0x12 },\
brunnobbco 0:561d07a737bc 89 { MODEM_FSK , REG_SYNCVALUE1 , 0xC1 },\
brunnobbco 0:561d07a737bc 90 { MODEM_FSK , REG_SYNCVALUE2 , 0x94 },\
brunnobbco 0:561d07a737bc 91 { MODEM_FSK , REG_SYNCVALUE3 , 0xC1 },\
brunnobbco 0:561d07a737bc 92 { MODEM_FSK , REG_PACKETCONFIG1 , 0xD8 },\
brunnobbco 0:561d07a737bc 93 { MODEM_FSK , REG_FIFOTHRESH , 0x8F },\
brunnobbco 0:561d07a737bc 94 { MODEM_FSK , REG_IMAGECAL , 0x02 },\
brunnobbco 0:561d07a737bc 95 { MODEM_FSK , REG_DIOMAPPING1 , 0x00 },\
brunnobbco 0:561d07a737bc 96 { MODEM_FSK , REG_DIOMAPPING2 , 0x30 },\
brunnobbco 0:561d07a737bc 97 { MODEM_LORA, REG_LR_DETECTOPTIMIZE , 0x43 },\
brunnobbco 0:561d07a737bc 98 { MODEM_LORA, REG_LR_PAYLOADMAXLENGTH, 0x40 },\
brunnobbco 0:561d07a737bc 99 }
brunnobbco 0:561d07a737bc 100
brunnobbco 0:561d07a737bc 101 const fsk_bw_t fsk_bandwidths[] =
brunnobbco 0:561d07a737bc 102 {
brunnobbco 0:561d07a737bc 103 { 2600 , 0x17 },
brunnobbco 0:561d07a737bc 104 { 3100 , 0x0F },
brunnobbco 0:561d07a737bc 105 { 3900 , 0x07 },
brunnobbco 0:561d07a737bc 106 { 5200 , 0x16 },
brunnobbco 0:561d07a737bc 107 { 6300 , 0x0E },
brunnobbco 0:561d07a737bc 108 { 7800 , 0x06 },
brunnobbco 0:561d07a737bc 109 { 10400 , 0x15 },
brunnobbco 0:561d07a737bc 110 { 12500 , 0x0D },
brunnobbco 0:561d07a737bc 111 { 15600 , 0x05 },
brunnobbco 0:561d07a737bc 112 { 20800 , 0x14 },
brunnobbco 0:561d07a737bc 113 { 25000 , 0x0C },
brunnobbco 0:561d07a737bc 114 { 31300 , 0x04 },
brunnobbco 0:561d07a737bc 115 { 41700 , 0x13 },
brunnobbco 0:561d07a737bc 116 { 50000 , 0x0B },
brunnobbco 0:561d07a737bc 117 { 62500 , 0x03 },
brunnobbco 0:561d07a737bc 118 { 83333 , 0x12 },
brunnobbco 0:561d07a737bc 119 { 100000, 0x0A },
brunnobbco 0:561d07a737bc 120 { 125000, 0x02 },
brunnobbco 0:561d07a737bc 121 { 166700, 0x11 },
brunnobbco 0:561d07a737bc 122 { 200000, 0x09 },
brunnobbco 0:561d07a737bc 123 { 250000, 0x01 },
brunnobbco 0:561d07a737bc 124 { 300000, 0x00 }, // Invalid bandwidth
brunnobbco 0:561d07a737bc 125 };
brunnobbco 0:561d07a737bc 126
brunnobbco 0:561d07a737bc 127 /**
brunnobbco 0:561d07a737bc 128 * SPI read/write masks
brunnobbco 0:561d07a737bc 129 */
brunnobbco 0:561d07a737bc 130 #define SPI_WRITE_CMD 0x80
brunnobbco 0:561d07a737bc 131 #define SPI_READ_CMD 0x7F
brunnobbco 0:561d07a737bc 132
brunnobbco 0:561d07a737bc 133 /**
brunnobbco 0:561d07a737bc 134 * Signals
brunnobbco 0:561d07a737bc 135 */
brunnobbco 0:561d07a737bc 136 #define SIG_DIO0 0x01
brunnobbco 0:561d07a737bc 137 #define SIG_DIO1 0x02
brunnobbco 0:561d07a737bc 138 #define SIG_DIO2 0x04
brunnobbco 0:561d07a737bc 139 #define SIG_DIO3 0x08
brunnobbco 1:3bdd6f917bf5 140 #define SIG_LRHOP 0x10
brunnobbco 1:3bdd6f917bf5 141 #define SIG_LRCAD 0x20
brunnobbco 0:561d07a737bc 142 #define SIG_TIMOUT 0x40
brunnobbco 0:561d07a737bc 143 #define SIG_RXSYNC 0x80
brunnobbco 0:561d07a737bc 144
brunnobbco 0:561d07a737bc 145 /**
brunnobbco 0:561d07a737bc 146 * Radio hardware registers initialization
brunnobbco 0:561d07a737bc 147 */
brunnobbco 0:561d07a737bc 148 static const radio_registers_t radio_reg_init[] = RADIO_INIT_REGISTERS_VALUE;
brunnobbco 0:561d07a737bc 149
brunnobbco 0:561d07a737bc 150
brunnobbco 0:561d07a737bc 151 /**
brunnobbco 0:561d07a737bc 152 * Constructor
brunnobbco 0:561d07a737bc 153 */
brunnobbco 0:561d07a737bc 154 SX1272_LoRaRadio::SX1272_LoRaRadio(PinName spi_mosi,
brunnobbco 0:561d07a737bc 155 PinName spi_miso,
brunnobbco 0:561d07a737bc 156 PinName spi_sclk,
brunnobbco 0:561d07a737bc 157 PinName nss,
brunnobbco 0:561d07a737bc 158 PinName reset,
brunnobbco 0:561d07a737bc 159 PinName dio0,
brunnobbco 0:561d07a737bc 160 PinName dio1,
brunnobbco 0:561d07a737bc 161 PinName dio2,
brunnobbco 0:561d07a737bc 162 PinName dio3,
brunnobbco 0:561d07a737bc 163 PinName dio4,
brunnobbco 0:561d07a737bc 164 PinName dio5,
brunnobbco 0:561d07a737bc 165 PinName rf_switch_ctl1,
brunnobbco 0:561d07a737bc 166 PinName rf_switch_ctl2,
brunnobbco 0:561d07a737bc 167 PinName txctl,
brunnobbco 0:561d07a737bc 168 PinName rxctl,
brunnobbco 0:561d07a737bc 169 PinName antswitch,
brunnobbco 0:561d07a737bc 170 PinName pwr_amp_ctl,
brunnobbco 0:561d07a737bc 171 PinName tcxo)
brunnobbco 0:561d07a737bc 172 : _spi(spi_mosi, spi_miso, spi_sclk),
brunnobbco 0:561d07a737bc 173 _chip_select(nss, 1),
brunnobbco 0:561d07a737bc 174 _reset_ctl(reset),
brunnobbco 1:3bdd6f917bf5 175 _dio0_ctl(dio0), _dio1_ctl(dio1), _dio2_ctl(dio2),
brunnobbco 0:561d07a737bc 176 _rf_switch_ctl1(rf_switch_ctl1, 0), _rf_switch_ctl2(rf_switch_ctl2, 0), _txctl(txctl, 0), _rxctl(rxctl, 0),
brunnobbco 3:bca9a8ee555d 177 _ant_switch(antswitch, 0),
brunnobbco 0:561d07a737bc 178 _pwr_amp_ctl(pwr_amp_ctl),
brunnobbco 0:561d07a737bc 179 _tcxo(tcxo)
brunnobbco 0:561d07a737bc 180
brunnobbco 0:561d07a737bc 181 #ifdef MBED_CONF_RTOS_PRESENT
brunnobbco 0:561d07a737bc 182 , irq_thread(osPriorityRealtime, 1024, NULL, "LR-SX1272")
brunnobbco 0:561d07a737bc 183 #endif
brunnobbco 0:561d07a737bc 184 {
brunnobbco 0:561d07a737bc 185 _rf_ctrls.ant_switch = antswitch;
brunnobbco 0:561d07a737bc 186 _rf_ctrls.pwr_amp_ctl = pwr_amp_ctl;
brunnobbco 0:561d07a737bc 187 _rf_ctrls.rf_switch_ctl1 = rf_switch_ctl1;
brunnobbco 0:561d07a737bc 188 _rf_ctrls.rf_switch_ctl2 = rf_switch_ctl2;
brunnobbco 0:561d07a737bc 189 _rf_ctrls.rxctl = rxctl;
brunnobbco 0:561d07a737bc 190 _rf_ctrls.txctl = txctl;
brunnobbco 0:561d07a737bc 191
brunnobbco 0:561d07a737bc 192 _dio1_pin = dio1;
brunnobbco 1:3bdd6f917bf5 193 _dio2_pin = dio2;
brunnobbco 0:561d07a737bc 194
brunnobbco 0:561d07a737bc 195 _radio_events = NULL;
brunnobbco 0:561d07a737bc 196
brunnobbco 0:561d07a737bc 197 if (tcxo != NC) {
brunnobbco 0:561d07a737bc 198 _tcxo = 1;
brunnobbco 0:561d07a737bc 199 }
brunnobbco 0:561d07a737bc 200
brunnobbco 0:561d07a737bc 201 radio_is_active = false;
brunnobbco 0:561d07a737bc 202
brunnobbco 0:561d07a737bc 203 #ifdef MBED_CONF_RTOS_PRESENT
brunnobbco 0:561d07a737bc 204 irq_thread.start(mbed::callback(this, &SX1272_LoRaRadio::rf_irq_task));
brunnobbco 0:561d07a737bc 205 #endif
brunnobbco 0:561d07a737bc 206 }
brunnobbco 0:561d07a737bc 207
brunnobbco 0:561d07a737bc 208 /**
brunnobbco 0:561d07a737bc 209 * Destructor
brunnobbco 0:561d07a737bc 210 */
brunnobbco 0:561d07a737bc 211 SX1272_LoRaRadio::~SX1272_LoRaRadio()
brunnobbco 0:561d07a737bc 212 {
brunnobbco 0:561d07a737bc 213
brunnobbco 0:561d07a737bc 214 }
brunnobbco 0:561d07a737bc 215
brunnobbco 0:561d07a737bc 216 /*****************************************************************************
brunnobbco 0:561d07a737bc 217 * Public APIs *
brunnobbco 0:561d07a737bc 218 ****************************************************************************/
brunnobbco 0:561d07a737bc 219
brunnobbco 0:561d07a737bc 220 /**
brunnobbco 0:561d07a737bc 221 * Acquire lock
brunnobbco 0:561d07a737bc 222 */
brunnobbco 0:561d07a737bc 223 void SX1272_LoRaRadio::lock(void)
brunnobbco 0:561d07a737bc 224 {
brunnobbco 0:561d07a737bc 225 mutex.lock();
brunnobbco 0:561d07a737bc 226 }
brunnobbco 0:561d07a737bc 227
brunnobbco 0:561d07a737bc 228 /**
brunnobbco 0:561d07a737bc 229 * Release lock
brunnobbco 0:561d07a737bc 230 */
brunnobbco 0:561d07a737bc 231 void SX1272_LoRaRadio::unlock(void)
brunnobbco 0:561d07a737bc 232 {
brunnobbco 0:561d07a737bc 233 mutex.unlock();
brunnobbco 0:561d07a737bc 234 }
brunnobbco 0:561d07a737bc 235
brunnobbco 0:561d07a737bc 236 /**
brunnobbco 0:561d07a737bc 237 * Initializes radio module
brunnobbco 0:561d07a737bc 238 */
brunnobbco 0:561d07a737bc 239 void SX1272_LoRaRadio::init_radio(radio_events_t *events)
brunnobbco 0:561d07a737bc 240 {
brunnobbco 0:561d07a737bc 241 _radio_events = events;
brunnobbco 0:561d07a737bc 242
brunnobbco 0:561d07a737bc 243 // Reset the radio transceiver
brunnobbco 0:561d07a737bc 244 radio_reset();
brunnobbco 0:561d07a737bc 245
brunnobbco 0:561d07a737bc 246 // Setup radio variant type
brunnobbco 0:561d07a737bc 247 set_sx1272_variant_type();
brunnobbco 0:561d07a737bc 248
brunnobbco 0:561d07a737bc 249 // setup SPI frequency
brunnobbco 0:561d07a737bc 250 // default is 8MHz although, configurable through
brunnobbco 0:561d07a737bc 251 // SPI_FREQUENCY macro
brunnobbco 0:561d07a737bc 252 setup_spi();
brunnobbco 0:561d07a737bc 253
brunnobbco 0:561d07a737bc 254 // set radio mode to sleep
brunnobbco 0:561d07a737bc 255 set_operation_mode(RF_OPMODE_SLEEP);
brunnobbco 0:561d07a737bc 256
brunnobbco 0:561d07a737bc 257 // Setup radio registers to defaults
brunnobbco 0:561d07a737bc 258 setup_registers();
brunnobbco 0:561d07a737bc 259
brunnobbco 0:561d07a737bc 260 // set modem type - defaults to FSK here
brunnobbco 0:561d07a737bc 261 set_modem(MODEM_FSK);
brunnobbco 0:561d07a737bc 262
brunnobbco 0:561d07a737bc 263 // set state to be idle
brunnobbco 0:561d07a737bc 264 _rf_settings.state = RF_IDLE;
brunnobbco 0:561d07a737bc 265
brunnobbco 0:561d07a737bc 266 // Setup interrupts on DIO pins
brunnobbco 0:561d07a737bc 267 setup_interrupts();
brunnobbco 0:561d07a737bc 268 }
brunnobbco 0:561d07a737bc 269
brunnobbco 0:561d07a737bc 270 /**
brunnobbco 0:561d07a737bc 271 * TODO: The purpose of this API is unclear.
brunnobbco 0:561d07a737bc 272 * Need to start an internal discussion.
brunnobbco 0:561d07a737bc 273 */
brunnobbco 0:561d07a737bc 274 bool SX1272_LoRaRadio::check_rf_frequency(uint32_t frequency)
brunnobbco 0:561d07a737bc 275 {
brunnobbco 0:561d07a737bc 276 // Implement check. Currently all frequencies are supported ? What band ?
brunnobbco 0:561d07a737bc 277 return true;
brunnobbco 0:561d07a737bc 278 }
brunnobbco 0:561d07a737bc 279
brunnobbco 0:561d07a737bc 280 /**
brunnobbco 0:561d07a737bc 281 * Sets up carrier frequency
brunnobbco 0:561d07a737bc 282 */
brunnobbco 0:561d07a737bc 283 void SX1272_LoRaRadio::set_channel(uint32_t freq)
brunnobbco 0:561d07a737bc 284 {
brunnobbco 0:561d07a737bc 285 _rf_settings.channel = freq;
brunnobbco 0:561d07a737bc 286 freq = (uint32_t) ((float) freq / (float) FREQ_STEP);
brunnobbco 0:561d07a737bc 287 write_to_register(REG_FRFMSB, (uint8_t) ((freq >> 16) & 0xFF));
brunnobbco 0:561d07a737bc 288 write_to_register(REG_FRFMID, (uint8_t) ((freq >> 8) & 0xFF));
brunnobbco 0:561d07a737bc 289 write_to_register(REG_FRFLSB, (uint8_t) (freq & 0xFF));
brunnobbco 0:561d07a737bc 290 }
brunnobbco 0:561d07a737bc 291
brunnobbco 0:561d07a737bc 292 /**
brunnobbco 0:561d07a737bc 293 * Returns current status of the radio state machine
brunnobbco 0:561d07a737bc 294 */
brunnobbco 0:561d07a737bc 295 uint8_t SX1272_LoRaRadio::get_status(void)
brunnobbco 0:561d07a737bc 296 {
brunnobbco 0:561d07a737bc 297 return _rf_settings.state;
brunnobbco 0:561d07a737bc 298 }
brunnobbco 0:561d07a737bc 299
brunnobbco 0:561d07a737bc 300 /**
brunnobbco 0:561d07a737bc 301 * sets the radio module to sleep
brunnobbco 0:561d07a737bc 302 */
brunnobbco 0:561d07a737bc 303
brunnobbco 0:561d07a737bc 304 void SX1272_LoRaRadio::sleep()
brunnobbco 0:561d07a737bc 305 {
brunnobbco 0:561d07a737bc 306 // stop timers
brunnobbco 0:561d07a737bc 307 tx_timeout_timer.detach();
brunnobbco 0:561d07a737bc 308 rx_sync_timer.detach();
brunnobbco 1:3bdd6f917bf5 309 lora_cad_timer.detach();
brunnobbco 1:3bdd6f917bf5 310 lora_hop_timer.detach();
brunnobbco 0:561d07a737bc 311
brunnobbco 0:561d07a737bc 312 // put module in sleep mode
brunnobbco 0:561d07a737bc 313 set_operation_mode(RF_OPMODE_SLEEP);
brunnobbco 0:561d07a737bc 314 }
brunnobbco 0:561d07a737bc 315
brunnobbco 0:561d07a737bc 316 /**
brunnobbco 0:561d07a737bc 317 * Sets up operation mode
brunnobbco 0:561d07a737bc 318 */
brunnobbco 0:561d07a737bc 319 void SX1272_LoRaRadio::set_operation_mode(uint8_t mode)
brunnobbco 0:561d07a737bc 320 {
brunnobbco 0:561d07a737bc 321 if (mode == RF_OPMODE_SLEEP) {
brunnobbco 0:561d07a737bc 322 set_low_power_mode(true);
brunnobbco 0:561d07a737bc 323 } else {
brunnobbco 0:561d07a737bc 324 set_low_power_mode(false);
brunnobbco 0:561d07a737bc 325 set_antenna_switch(mode);
brunnobbco 0:561d07a737bc 326 }
brunnobbco 0:561d07a737bc 327
brunnobbco 0:561d07a737bc 328 write_to_register(REG_OPMODE, (read_register(REG_OPMODE) & RF_OPMODE_MASK) | mode);
brunnobbco 0:561d07a737bc 329 }
brunnobbco 0:561d07a737bc 330
brunnobbco 0:561d07a737bc 331 /**
brunnobbco 0:561d07a737bc 332 * Sets the modem type to use
brunnobbco 0:561d07a737bc 333 *
brunnobbco 0:561d07a737bc 334 * At initialization FSK is chosen. Later stack or application
brunnobbco 0:561d07a737bc 335 * can choose to change.
brunnobbco 0:561d07a737bc 336 */
brunnobbco 0:561d07a737bc 337 void SX1272_LoRaRadio::set_modem(uint8_t modem)
brunnobbco 0:561d07a737bc 338 {
brunnobbco 0:561d07a737bc 339 if ((read_register(REG_OPMODE) & RFLR_OPMODE_LONGRANGEMODE_ON) != 0 ) {
brunnobbco 0:561d07a737bc 340 _rf_settings.modem = MODEM_LORA;
brunnobbco 0:561d07a737bc 341 } else {
brunnobbco 0:561d07a737bc 342 _rf_settings.modem = MODEM_FSK;
brunnobbco 0:561d07a737bc 343 }
brunnobbco 0:561d07a737bc 344
brunnobbco 0:561d07a737bc 345 if(_rf_settings.modem == modem ) {
brunnobbco 0:561d07a737bc 346 // if the modem is already set
brunnobbco 0:561d07a737bc 347 return;
brunnobbco 0:561d07a737bc 348 }
brunnobbco 0:561d07a737bc 349
brunnobbco 0:561d07a737bc 350 _rf_settings.modem = modem;
brunnobbco 0:561d07a737bc 351
brunnobbco 0:561d07a737bc 352 switch(_rf_settings.modem)
brunnobbco 0:561d07a737bc 353 {
brunnobbco 0:561d07a737bc 354 default:
brunnobbco 0:561d07a737bc 355 case MODEM_FSK:
brunnobbco 0:561d07a737bc 356 // before changing modem mode, put the module to sleep
brunnobbco 0:561d07a737bc 357 sleep();
brunnobbco 0:561d07a737bc 358 write_to_register(REG_OPMODE, (read_register(REG_OPMODE) & RFLR_OPMODE_LONGRANGEMODE_MASK)
brunnobbco 0:561d07a737bc 359 | RFLR_OPMODE_LONGRANGEMODE_OFF);
brunnobbco 0:561d07a737bc 360
brunnobbco 0:561d07a737bc 361 // Datasheet Tables 28, 29 DIO mapping
brunnobbco 0:561d07a737bc 362 write_to_register(REG_DIOMAPPING1, 0x00); // sets DIO0-DI03 in default mode
brunnobbco 0:561d07a737bc 363 write_to_register(REG_DIOMAPPING2, 0x30); // bits 4-5 are turned on i.e.,
brunnobbco 0:561d07a737bc 364 // DIO5 and DIO4=ModeReady
brunnobbco 0:561d07a737bc 365 break;
brunnobbco 0:561d07a737bc 366 case MODEM_LORA:
brunnobbco 0:561d07a737bc 367 sleep();
brunnobbco 0:561d07a737bc 368 write_to_register(REG_OPMODE, (read_register(REG_OPMODE) & RFLR_OPMODE_LONGRANGEMODE_MASK)
brunnobbco 0:561d07a737bc 369 | RFLR_OPMODE_LONGRANGEMODE_ON);
brunnobbco 0:561d07a737bc 370
brunnobbco 0:561d07a737bc 371 // Datasheet Tables 17 DIO mapping for LoRa
brunnobbco 0:561d07a737bc 372 // set to defaults
brunnobbco 0:561d07a737bc 373 write_to_register(REG_DIOMAPPING1, 0x00); // DIO0 - DIO3 defaults
brunnobbco 0:561d07a737bc 374 write_to_register(REG_DIOMAPPING2, 0x00); // DIO4 - DIO5 defaults
brunnobbco 0:561d07a737bc 375
brunnobbco 0:561d07a737bc 376 break;
brunnobbco 0:561d07a737bc 377 }
brunnobbco 0:561d07a737bc 378 }
brunnobbco 0:561d07a737bc 379
brunnobbco 0:561d07a737bc 380 /**
brunnobbco 0:561d07a737bc 381 * Can be used by application/stack or the driver itself
brunnobbco 0:561d07a737bc 382 * Ref: Datasheet 7.2.2 Manual Reset
brunnobbco 0:561d07a737bc 383 */
brunnobbco 0:561d07a737bc 384 void SX1272_LoRaRadio::radio_reset()
brunnobbco 0:561d07a737bc 385 {
brunnobbco 0:561d07a737bc 386 _reset_ctl.output();
brunnobbco 0:561d07a737bc 387 _reset_ctl = 0;
brunnobbco 0:561d07a737bc 388 wait_ms(2);
brunnobbco 0:561d07a737bc 389 _reset_ctl.input();
brunnobbco 0:561d07a737bc 390 wait_ms(6);
brunnobbco 0:561d07a737bc 391 }
brunnobbco 0:561d07a737bc 392
brunnobbco 0:561d07a737bc 393 /**
brunnobbco 0:561d07a737bc 394 * Sets up receiver related configurations
brunnobbco 0:561d07a737bc 395 *
brunnobbco 0:561d07a737bc 396 * Must be called before setting the radio in rx mode
brunnobbco 0:561d07a737bc 397 */
brunnobbco 0:561d07a737bc 398 void SX1272_LoRaRadio::set_rx_config(radio_modems_t modem, uint32_t bandwidth,
brunnobbco 0:561d07a737bc 399 uint32_t datarate, uint8_t coderate,
brunnobbco 0:561d07a737bc 400 uint32_t bandwidth_afc, uint16_t preamble_len,
brunnobbco 0:561d07a737bc 401 uint16_t symb_timeout, bool fix_len,
brunnobbco 0:561d07a737bc 402 uint8_t payload_len,
brunnobbco 0:561d07a737bc 403 bool crc_on, bool freq_hop_on, uint8_t hop_period,
brunnobbco 0:561d07a737bc 404 bool iq_inverted, bool rx_continuous)
brunnobbco 0:561d07a737bc 405 {
brunnobbco 0:561d07a737bc 406 set_modem(modem);
brunnobbco 0:561d07a737bc 407
brunnobbco 0:561d07a737bc 408 switch (modem) {
brunnobbco 0:561d07a737bc 409 case MODEM_FSK:
brunnobbco 0:561d07a737bc 410 _rf_settings.fsk.bandwidth = bandwidth;
brunnobbco 0:561d07a737bc 411 _rf_settings.fsk.datarate = datarate;
brunnobbco 0:561d07a737bc 412 _rf_settings.fsk.bandwidth_afc = bandwidth_afc;
brunnobbco 0:561d07a737bc 413 _rf_settings.fsk.fix_len = fix_len;
brunnobbco 0:561d07a737bc 414 _rf_settings.fsk.payload_len = payload_len;
brunnobbco 0:561d07a737bc 415 _rf_settings.fsk.crc_on = crc_on;
brunnobbco 0:561d07a737bc 416 _rf_settings.fsk.iq_inverted = iq_inverted;
brunnobbco 0:561d07a737bc 417 _rf_settings.fsk.rx_continuous = rx_continuous;
brunnobbco 0:561d07a737bc 418 _rf_settings.fsk.preamble_len = preamble_len;
brunnobbco 0:561d07a737bc 419 _rf_settings.fsk.rx_single_timeout = (symb_timeout + 1) / 2; // dividing by 2 as our detector size is 2 symbols (16 bytes)
brunnobbco 0:561d07a737bc 420
brunnobbco 0:561d07a737bc 421 datarate = (uint16_t) ((float) XTAL_FREQ / (float) datarate);
brunnobbco 0:561d07a737bc 422 write_to_register(REG_BITRATEMSB, (uint8_t) (datarate >> 8));
brunnobbco 0:561d07a737bc 423 write_to_register(REG_BITRATELSB, (uint8_t) (datarate & 0xFF));
brunnobbco 0:561d07a737bc 424
brunnobbco 0:561d07a737bc 425 write_to_register(REG_RXBW, get_fsk_bw_reg_val(bandwidth));
brunnobbco 0:561d07a737bc 426 write_to_register(REG_AFCBW, get_fsk_bw_reg_val(bandwidth_afc));
brunnobbco 0:561d07a737bc 427
brunnobbco 0:561d07a737bc 428 write_to_register(REG_PREAMBLEMSB, (uint8_t) ((preamble_len >> 8) & 0xFF));
brunnobbco 0:561d07a737bc 429 write_to_register(REG_PREAMBLELSB, (uint8_t) (preamble_len & 0xFF));
brunnobbco 0:561d07a737bc 430
brunnobbco 0:561d07a737bc 431 if (fix_len == 1) {
brunnobbco 0:561d07a737bc 432 write_to_register(REG_PAYLOADLENGTH, payload_len);
brunnobbco 0:561d07a737bc 433 } else {
brunnobbco 0:561d07a737bc 434 write_to_register(REG_PAYLOADLENGTH, 0xFF); // Set payload length to the maximum
brunnobbco 0:561d07a737bc 435 }
brunnobbco 0:561d07a737bc 436
brunnobbco 0:561d07a737bc 437 write_to_register(REG_PACKETCONFIG1, (read_register(REG_PACKETCONFIG1) & RF_PACKETCONFIG1_CRC_MASK
brunnobbco 0:561d07a737bc 438 & RF_PACKETCONFIG1_PACKETFORMAT_MASK)
brunnobbco 0:561d07a737bc 439 | ((fix_len == 1) ?
brunnobbco 0:561d07a737bc 440 RF_PACKETCONFIG1_PACKETFORMAT_FIXED :
brunnobbco 0:561d07a737bc 441 RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE)
brunnobbco 0:561d07a737bc 442 | (crc_on << 4));
brunnobbco 0:561d07a737bc 443
brunnobbco 0:561d07a737bc 444 // TODO why packet mode 2 ?
brunnobbco 0:561d07a737bc 445 write_to_register(REG_PACKETCONFIG2, (read_register(REG_PACKETCONFIG2) | RF_PACKETCONFIG2_DATAMODE_PACKET));
brunnobbco 0:561d07a737bc 446
brunnobbco 0:561d07a737bc 447 break;
brunnobbco 0:561d07a737bc 448
brunnobbco 0:561d07a737bc 449 case MODEM_LORA:
brunnobbco 0:561d07a737bc 450 _rf_settings.lora.bandwidth = bandwidth;
brunnobbco 0:561d07a737bc 451 _rf_settings.lora.datarate = datarate;
brunnobbco 0:561d07a737bc 452 _rf_settings.lora.coderate = coderate;
brunnobbco 0:561d07a737bc 453 _rf_settings.lora.preamble_len = preamble_len;
brunnobbco 0:561d07a737bc 454 _rf_settings.lora.fix_len = fix_len;
brunnobbco 0:561d07a737bc 455 _rf_settings.lora.payload_len = payload_len;
brunnobbco 0:561d07a737bc 456 _rf_settings.lora.crc_on = crc_on;
brunnobbco 0:561d07a737bc 457 _rf_settings.lora.freq_hop_on = freq_hop_on;
brunnobbco 0:561d07a737bc 458 _rf_settings.lora.hop_period = hop_period;
brunnobbco 0:561d07a737bc 459 _rf_settings.lora.iq_inverted = iq_inverted;
brunnobbco 0:561d07a737bc 460 _rf_settings.lora.rx_continuous = rx_continuous;
brunnobbco 0:561d07a737bc 461
brunnobbco 0:561d07a737bc 462 if (datarate > 12) {
brunnobbco 0:561d07a737bc 463 datarate = 12;
brunnobbco 0:561d07a737bc 464 } else if (datarate < 6) {
brunnobbco 0:561d07a737bc 465 datarate = 6;
brunnobbco 0:561d07a737bc 466 }
brunnobbco 0:561d07a737bc 467
brunnobbco 0:561d07a737bc 468 if (((bandwidth == 0) && ((datarate == 11) || (datarate == 12)))
brunnobbco 0:561d07a737bc 469 || ((bandwidth == 1) && (datarate == 12))) {
brunnobbco 0:561d07a737bc 470 _rf_settings.lora.low_datarate_optimize = 0x01;
brunnobbco 0:561d07a737bc 471 } else {
brunnobbco 0:561d07a737bc 472 _rf_settings.lora.low_datarate_optimize = 0x00;
brunnobbco 0:561d07a737bc 473 }
brunnobbco 0:561d07a737bc 474
brunnobbco 0:561d07a737bc 475 write_to_register(REG_LR_MODEMCONFIG1, (read_register(REG_LR_MODEMCONFIG1) & RFLR_MODEMCONFIG1_BW_MASK
brunnobbco 0:561d07a737bc 476 & RFLR_MODEMCONFIG1_CODINGRATE_MASK
brunnobbco 0:561d07a737bc 477 & RFLR_MODEMCONFIG1_IMPLICITHEADER_MASK
brunnobbco 0:561d07a737bc 478 & RFLR_MODEMCONFIG1_RXPAYLOADCRC_MASK & RFLR_MODEMCONFIG1_LOWDATARATEOPTIMIZE_MASK)
brunnobbco 0:561d07a737bc 479 | (bandwidth << 6)
brunnobbco 0:561d07a737bc 480 | (coderate << 3) | (fix_len << 2) | (crc_on << 1)
brunnobbco 0:561d07a737bc 481 | _rf_settings.lora.low_datarate_optimize);
brunnobbco 0:561d07a737bc 482
brunnobbco 0:561d07a737bc 483 write_to_register(REG_LR_MODEMCONFIG2, (read_register(REG_LR_MODEMCONFIG2) & RFLR_MODEMCONFIG2_SF_MASK
brunnobbco 0:561d07a737bc 484 & RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK)
brunnobbco 0:561d07a737bc 485 | (datarate << 4)
brunnobbco 0:561d07a737bc 486 | ((symb_timeout >> 8)
brunnobbco 0:561d07a737bc 487 & ~RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK));
brunnobbco 0:561d07a737bc 488
brunnobbco 0:561d07a737bc 489 write_to_register(REG_LR_SYMBTIMEOUTLSB, (uint8_t) (symb_timeout & 0xFF));
brunnobbco 0:561d07a737bc 490
brunnobbco 0:561d07a737bc 491 write_to_register(REG_LR_PREAMBLEMSB, (uint8_t) ((preamble_len >> 8) & 0xFF));
brunnobbco 0:561d07a737bc 492 write_to_register(REG_LR_PREAMBLELSB, (uint8_t) (preamble_len & 0xFF));
brunnobbco 0:561d07a737bc 493
brunnobbco 0:561d07a737bc 494 if (fix_len == 1) {
brunnobbco 0:561d07a737bc 495 write_to_register(REG_LR_PAYLOADLENGTH, payload_len);
brunnobbco 0:561d07a737bc 496 }
brunnobbco 0:561d07a737bc 497
brunnobbco 0:561d07a737bc 498 if (_rf_settings.lora.freq_hop_on == true) {
brunnobbco 0:561d07a737bc 499 write_to_register( REG_LR_PLLHOP, (read_register(REG_LR_PLLHOP) & RFLR_PLLHOP_FASTHOP_MASK)
brunnobbco 0:561d07a737bc 500 | RFLR_PLLHOP_FASTHOP_ON);
brunnobbco 0:561d07a737bc 501 write_to_register( REG_LR_HOPPERIOD, _rf_settings.lora.hop_period);
brunnobbco 0:561d07a737bc 502 }
brunnobbco 0:561d07a737bc 503
brunnobbco 0:561d07a737bc 504 if (datarate == 6) {
brunnobbco 0:561d07a737bc 505 write_to_register( REG_LR_DETECTOPTIMIZE, (read_register(REG_LR_DETECTOPTIMIZE) & RFLR_DETECTIONOPTIMIZE_MASK)
brunnobbco 0:561d07a737bc 506 | RFLR_DETECTIONOPTIMIZE_SF6);
brunnobbco 0:561d07a737bc 507 write_to_register( REG_LR_DETECTIONTHRESHOLD, RFLR_DETECTIONTHRESH_SF6);
brunnobbco 0:561d07a737bc 508 } else {
brunnobbco 0:561d07a737bc 509 write_to_register(REG_LR_DETECTOPTIMIZE, (read_register(REG_LR_DETECTOPTIMIZE) & RFLR_DETECTIONOPTIMIZE_MASK)
brunnobbco 0:561d07a737bc 510 | RFLR_DETECTIONOPTIMIZE_SF7_TO_SF12);
brunnobbco 0:561d07a737bc 511 write_to_register( REG_LR_DETECTIONTHRESHOLD, RFLR_DETECTIONTHRESH_SF7_TO_SF12);
brunnobbco 0:561d07a737bc 512 }
brunnobbco 0:561d07a737bc 513
brunnobbco 0:561d07a737bc 514 break;
brunnobbco 0:561d07a737bc 515
brunnobbco 0:561d07a737bc 516 default:
brunnobbco 0:561d07a737bc 517 break;
brunnobbco 0:561d07a737bc 518 }
brunnobbco 0:561d07a737bc 519 }
brunnobbco 0:561d07a737bc 520
brunnobbco 0:561d07a737bc 521 /**
brunnobbco 0:561d07a737bc 522 * Sets up transmitter related configuration
brunnobbco 0:561d07a737bc 523 *
brunnobbco 0:561d07a737bc 524 * Must be called before putting the radio module in Tx mode or trying
brunnobbco 0:561d07a737bc 525 * to send
brunnobbco 0:561d07a737bc 526 */
brunnobbco 0:561d07a737bc 527 void SX1272_LoRaRadio::set_tx_config(radio_modems_t modem, int8_t power,
brunnobbco 0:561d07a737bc 528 uint32_t fdev, uint32_t bandwidth,
brunnobbco 0:561d07a737bc 529 uint32_t datarate, uint8_t coderate,
brunnobbco 0:561d07a737bc 530 uint16_t preamble_len, bool fix_len,
brunnobbco 0:561d07a737bc 531 bool crc_on, bool freq_hop_on,
brunnobbco 0:561d07a737bc 532 uint8_t hop_period, bool iq_inverted,
brunnobbco 0:561d07a737bc 533 uint32_t timeout)
brunnobbco 0:561d07a737bc 534 {
brunnobbco 0:561d07a737bc 535 set_modem(modem);
brunnobbco 0:561d07a737bc 536 set_rf_tx_power(power);
brunnobbco 0:561d07a737bc 537
brunnobbco 0:561d07a737bc 538 switch (modem) {
brunnobbco 0:561d07a737bc 539 case MODEM_FSK:
brunnobbco 0:561d07a737bc 540 _rf_settings.fsk.power = power;
brunnobbco 0:561d07a737bc 541 _rf_settings.fsk.f_dev = fdev;
brunnobbco 0:561d07a737bc 542 _rf_settings.fsk.bandwidth = bandwidth;
brunnobbco 0:561d07a737bc 543 _rf_settings.fsk.datarate = datarate;
brunnobbco 0:561d07a737bc 544 _rf_settings.fsk.preamble_len = preamble_len;
brunnobbco 0:561d07a737bc 545 _rf_settings.fsk.fix_len = fix_len;
brunnobbco 0:561d07a737bc 546 _rf_settings.fsk.crc_on = crc_on;
brunnobbco 0:561d07a737bc 547 _rf_settings.fsk.iq_inverted = iq_inverted;
brunnobbco 0:561d07a737bc 548 _rf_settings.fsk.tx_timeout = timeout;
brunnobbco 0:561d07a737bc 549
brunnobbco 0:561d07a737bc 550 fdev = (uint16_t) ((float) fdev / (float) FREQ_STEP);
brunnobbco 0:561d07a737bc 551 write_to_register( REG_FDEVMSB, (uint8_t) (fdev >> 8));
brunnobbco 0:561d07a737bc 552 write_to_register( REG_FDEVLSB, (uint8_t) (fdev & 0xFF));
brunnobbco 0:561d07a737bc 553
brunnobbco 0:561d07a737bc 554 datarate = (uint16_t) ((float) XTAL_FREQ / (float) datarate);
brunnobbco 0:561d07a737bc 555 write_to_register( REG_BITRATEMSB, (uint8_t) (datarate >> 8));
brunnobbco 0:561d07a737bc 556 write_to_register( REG_BITRATELSB, (uint8_t) (datarate & 0xFF));
brunnobbco 0:561d07a737bc 557
brunnobbco 0:561d07a737bc 558 write_to_register( REG_PREAMBLEMSB, (preamble_len >> 8) & 0x00FF);
brunnobbco 0:561d07a737bc 559 write_to_register( REG_PREAMBLELSB, preamble_len & 0xFF);
brunnobbco 0:561d07a737bc 560
brunnobbco 0:561d07a737bc 561
brunnobbco 0:561d07a737bc 562 write_to_register(REG_PACKETCONFIG1, (read_register(REG_PACKETCONFIG1)
brunnobbco 0:561d07a737bc 563 & RF_PACKETCONFIG1_CRC_MASK
brunnobbco 0:561d07a737bc 564 & RF_PACKETCONFIG1_PACKETFORMAT_MASK)
brunnobbco 0:561d07a737bc 565 | ((fix_len == 1) ?
brunnobbco 0:561d07a737bc 566 RF_PACKETCONFIG1_PACKETFORMAT_FIXED :
brunnobbco 0:561d07a737bc 567 RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE)
brunnobbco 0:561d07a737bc 568 | (crc_on << 4));
brunnobbco 0:561d07a737bc 569
brunnobbco 0:561d07a737bc 570 //cfg_mode = read_register(REG_PACKETCONFIG2);
brunnobbco 0:561d07a737bc 571 write_to_register(REG_PACKETCONFIG2, read_register(REG_PACKETCONFIG2)
brunnobbco 0:561d07a737bc 572 | RF_PACKETCONFIG2_DATAMODE_PACKET);
brunnobbco 0:561d07a737bc 573
brunnobbco 0:561d07a737bc 574 break;
brunnobbco 0:561d07a737bc 575
brunnobbco 0:561d07a737bc 576 case MODEM_LORA:
brunnobbco 0:561d07a737bc 577 _rf_settings.lora.power = power;
brunnobbco 0:561d07a737bc 578 _rf_settings.lora.bandwidth = bandwidth;
brunnobbco 0:561d07a737bc 579 _rf_settings.lora.datarate = datarate;
brunnobbco 0:561d07a737bc 580 _rf_settings.lora.coderate = coderate;
brunnobbco 0:561d07a737bc 581 _rf_settings.lora.preamble_len = preamble_len;
brunnobbco 0:561d07a737bc 582 _rf_settings.lora.fix_len = fix_len;
brunnobbco 0:561d07a737bc 583 _rf_settings.lora.freq_hop_on = freq_hop_on;
brunnobbco 0:561d07a737bc 584 _rf_settings.lora.hop_period = hop_period;
brunnobbco 0:561d07a737bc 585 _rf_settings.lora.crc_on = crc_on;
brunnobbco 0:561d07a737bc 586 _rf_settings.lora.iq_inverted = iq_inverted;
brunnobbco 0:561d07a737bc 587 _rf_settings.lora.tx_timeout = timeout;
brunnobbco 0:561d07a737bc 588
brunnobbco 0:561d07a737bc 589 if (datarate > 12) {
brunnobbco 0:561d07a737bc 590 datarate = 12;
brunnobbco 0:561d07a737bc 591 } else if (datarate < 6) {
brunnobbco 0:561d07a737bc 592 datarate = 6;
brunnobbco 0:561d07a737bc 593 }
brunnobbco 0:561d07a737bc 594 if (((bandwidth == 0) && ((datarate == 11) || (datarate == 12)))
brunnobbco 0:561d07a737bc 595 || ((bandwidth == 1) && (datarate == 12))) {
brunnobbco 0:561d07a737bc 596 _rf_settings.lora.low_datarate_optimize = 0x01;
brunnobbco 0:561d07a737bc 597 } else {
brunnobbco 0:561d07a737bc 598 _rf_settings.lora.low_datarate_optimize = 0x00;
brunnobbco 0:561d07a737bc 599 }
brunnobbco 0:561d07a737bc 600
brunnobbco 0:561d07a737bc 601 if (_rf_settings.lora.freq_hop_on == true) {
brunnobbco 0:561d07a737bc 602 write_to_register(REG_LR_PLLHOP, (read_register(REG_LR_PLLHOP)
brunnobbco 0:561d07a737bc 603 & RFLR_PLLHOP_FASTHOP_MASK)
brunnobbco 0:561d07a737bc 604 | RFLR_PLLHOP_FASTHOP_ON);
brunnobbco 0:561d07a737bc 605 write_to_register(REG_LR_HOPPERIOD, _rf_settings.lora.hop_period);
brunnobbco 0:561d07a737bc 606 }
brunnobbco 0:561d07a737bc 607
brunnobbco 0:561d07a737bc 608 write_to_register(REG_LR_MODEMCONFIG1, (read_register(REG_LR_MODEMCONFIG1) &
brunnobbco 0:561d07a737bc 609 RFLR_MODEMCONFIG1_BW_MASK &
brunnobbco 0:561d07a737bc 610 RFLR_MODEMCONFIG1_CODINGRATE_MASK &
brunnobbco 0:561d07a737bc 611 RFLR_MODEMCONFIG1_IMPLICITHEADER_MASK &
brunnobbco 0:561d07a737bc 612 RFLR_MODEMCONFIG1_RXPAYLOADCRC_MASK &
brunnobbco 0:561d07a737bc 613 RFLR_MODEMCONFIG1_LOWDATARATEOPTIMIZE_MASK)
brunnobbco 0:561d07a737bc 614 | (bandwidth << 6) | (coderate << 3)
brunnobbco 0:561d07a737bc 615 | (fix_len << 2) | (crc_on << 1)
brunnobbco 0:561d07a737bc 616 | _rf_settings.lora.low_datarate_optimize);
brunnobbco 0:561d07a737bc 617
brunnobbco 0:561d07a737bc 618 write_to_register(REG_LR_MODEMCONFIG2,
brunnobbco 0:561d07a737bc 619 (read_register(REG_LR_MODEMCONFIG2) &
brunnobbco 0:561d07a737bc 620 RFLR_MODEMCONFIG2_SF_MASK) | (datarate << 4));
brunnobbco 0:561d07a737bc 621
brunnobbco 0:561d07a737bc 622 write_to_register( REG_LR_PREAMBLEMSB, (preamble_len >> 8) & 0x00FF);
brunnobbco 0:561d07a737bc 623 write_to_register( REG_LR_PREAMBLELSB, preamble_len & 0xFF);
brunnobbco 0:561d07a737bc 624
brunnobbco 0:561d07a737bc 625 if (datarate == 6) {
brunnobbco 0:561d07a737bc 626 write_to_register(REG_LR_DETECTOPTIMIZE,
brunnobbco 0:561d07a737bc 627 (read_register(REG_LR_DETECTOPTIMIZE) &
brunnobbco 0:561d07a737bc 628 RFLR_DETECTIONOPTIMIZE_MASK) |
brunnobbco 0:561d07a737bc 629 RFLR_DETECTIONOPTIMIZE_SF6);
brunnobbco 0:561d07a737bc 630 write_to_register( REG_LR_DETECTIONTHRESHOLD,
brunnobbco 0:561d07a737bc 631 RFLR_DETECTIONTHRESH_SF6);
brunnobbco 0:561d07a737bc 632 } else {
brunnobbco 0:561d07a737bc 633 write_to_register(REG_LR_DETECTOPTIMIZE,
brunnobbco 0:561d07a737bc 634 (read_register(REG_LR_DETECTOPTIMIZE) &
brunnobbco 0:561d07a737bc 635 RFLR_DETECTIONOPTIMIZE_MASK) |
brunnobbco 0:561d07a737bc 636 RFLR_DETECTIONOPTIMIZE_SF7_TO_SF12);
brunnobbco 0:561d07a737bc 637 write_to_register(REG_LR_DETECTIONTHRESHOLD,
brunnobbco 0:561d07a737bc 638 RFLR_DETECTIONTHRESH_SF7_TO_SF12);
brunnobbco 0:561d07a737bc 639 }
brunnobbco 0:561d07a737bc 640
brunnobbco 0:561d07a737bc 641 break;
brunnobbco 0:561d07a737bc 642 }
brunnobbco 0:561d07a737bc 643 }
brunnobbco 0:561d07a737bc 644
brunnobbco 0:561d07a737bc 645 /**
brunnobbco 0:561d07a737bc 646 * Calculates time on Air i.e., dwell time for a single packet
brunnobbco 0:561d07a737bc 647 *
brunnobbco 0:561d07a737bc 648 * Crucial for the stack in order to calculate dwell time so as to control
brunnobbco 0:561d07a737bc 649 * duty cycling.
brunnobbco 0:561d07a737bc 650 */
brunnobbco 0:561d07a737bc 651 uint32_t SX1272_LoRaRadio::time_on_air(radio_modems_t modem, uint8_t pkt_len)
brunnobbco 0:561d07a737bc 652 {
brunnobbco 0:561d07a737bc 653 uint32_t airtime = 0;
brunnobbco 0:561d07a737bc 654
brunnobbco 0:561d07a737bc 655 switch (modem) {
brunnobbco 0:561d07a737bc 656 case MODEM_FSK: {
brunnobbco 0:561d07a737bc 657 airtime = rint((8 * (_rf_settings.fsk.preamble_len
brunnobbco 0:561d07a737bc 658 + ((read_register( REG_SYNCCONFIG)
brunnobbco 0:561d07a737bc 659 & ~RF_SYNCCONFIG_SYNCSIZE_MASK) + 1)
brunnobbco 0:561d07a737bc 660 + ((_rf_settings.fsk.fix_len == 0x01) ?
brunnobbco 0:561d07a737bc 661 0.0f : 1.0f)
brunnobbco 0:561d07a737bc 662 + (((read_register( REG_PACKETCONFIG1)
brunnobbco 0:561d07a737bc 663 & ~RF_PACKETCONFIG1_ADDRSFILTERING_MASK)
brunnobbco 0:561d07a737bc 664 != 0x00) ? 1.0f : 0) + pkt_len
brunnobbco 0:561d07a737bc 665 + ((_rf_settings.fsk.crc_on == 0x01) ?
brunnobbco 0:561d07a737bc 666 2.0f : 0))
brunnobbco 0:561d07a737bc 667 / _rf_settings.fsk.datarate) * 1000);
brunnobbco 0:561d07a737bc 668 }
brunnobbco 0:561d07a737bc 669 break;
brunnobbco 0:561d07a737bc 670 case MODEM_LORA: {
brunnobbco 0:561d07a737bc 671 float bw = 0.0f;
brunnobbco 0:561d07a737bc 672 switch (_rf_settings.lora.bandwidth) {
brunnobbco 0:561d07a737bc 673 case 0: // 125 kHz
brunnobbco 0:561d07a737bc 674 bw = 125000;
brunnobbco 0:561d07a737bc 675 break;
brunnobbco 0:561d07a737bc 676 case 1: // 250 kHz
brunnobbco 0:561d07a737bc 677 bw = 250000;
brunnobbco 0:561d07a737bc 678 break;
brunnobbco 0:561d07a737bc 679 case 2: // 500 kHz
brunnobbco 0:561d07a737bc 680 bw = 500000;
brunnobbco 0:561d07a737bc 681 break;
brunnobbco 0:561d07a737bc 682 }
brunnobbco 0:561d07a737bc 683
brunnobbco 0:561d07a737bc 684 // Symbol rate : time for one symbol (secs)
brunnobbco 0:561d07a737bc 685 float rs = bw / (1 << _rf_settings.lora.datarate);
brunnobbco 0:561d07a737bc 686 float ts = 1 / rs;
brunnobbco 0:561d07a737bc 687 // time of preamble
brunnobbco 0:561d07a737bc 688 float preamble_time = (_rf_settings.lora.preamble_len + 4.25f) * ts;
brunnobbco 0:561d07a737bc 689 // Symbol length of payload and time
brunnobbco 0:561d07a737bc 690 float tmp = ceil((8 * pkt_len - 4 * _rf_settings.lora.datarate + 28
brunnobbco 0:561d07a737bc 691 + 16 * _rf_settings.lora.crc_on -
brunnobbco 0:561d07a737bc 692 (_rf_settings.lora.fix_len ? 20 : 0))
brunnobbco 0:561d07a737bc 693 / (float) (4 * (_rf_settings.lora.datarate -
brunnobbco 0:561d07a737bc 694 ((_rf_settings.lora.low_datarate_optimize
brunnobbco 0:561d07a737bc 695 > 0) ? 2 : 0)))) *
brunnobbco 0:561d07a737bc 696 (_rf_settings.lora.coderate + 4);
brunnobbco 0:561d07a737bc 697 float n_payload = 8 + ((tmp > 0) ? tmp : 0);
brunnobbco 0:561d07a737bc 698 float t_payload = n_payload * ts;
brunnobbco 0:561d07a737bc 699 // Time on air
brunnobbco 0:561d07a737bc 700 float t_onair = preamble_time + t_payload;
brunnobbco 0:561d07a737bc 701 // return ms secs
brunnobbco 0:561d07a737bc 702 airtime = floor(t_onair * 1000 + 0.999f);
brunnobbco 0:561d07a737bc 703 }
brunnobbco 0:561d07a737bc 704 break;
brunnobbco 0:561d07a737bc 705 }
brunnobbco 0:561d07a737bc 706 return airtime;
brunnobbco 0:561d07a737bc 707 }
brunnobbco 0:561d07a737bc 708
brunnobbco 0:561d07a737bc 709 /**
brunnobbco 0:561d07a737bc 710 * Prepares and sends the radio packet out in the air
brunnobbco 0:561d07a737bc 711 */
brunnobbco 0:561d07a737bc 712 void SX1272_LoRaRadio::send(uint8_t *buffer, uint8_t size)
brunnobbco 0:561d07a737bc 713 {
brunnobbco 0:561d07a737bc 714 uint32_t tx_timeout = 0;
brunnobbco 0:561d07a737bc 715
brunnobbco 0:561d07a737bc 716 switch (_rf_settings.modem) {
brunnobbco 0:561d07a737bc 717 case MODEM_FSK:
brunnobbco 0:561d07a737bc 718
brunnobbco 0:561d07a737bc 719 _rf_settings.fsk_packet_handler.nb_bytes = 0;
brunnobbco 0:561d07a737bc 720 _rf_settings.fsk_packet_handler.size = size;
brunnobbco 0:561d07a737bc 721
brunnobbco 0:561d07a737bc 722 // FIFO operations can not take place in Sleep mode
brunnobbco 0:561d07a737bc 723 if ((read_register(REG_OPMODE) & ~RF_OPMODE_MASK) == RF_OPMODE_SLEEP) {
brunnobbco 0:561d07a737bc 724 standby();
brunnobbco 0:561d07a737bc 725 wait_ms(1);
brunnobbco 0:561d07a737bc 726 }
brunnobbco 0:561d07a737bc 727
brunnobbco 0:561d07a737bc 728 if (_rf_settings.fsk.fix_len == false) {
brunnobbco 0:561d07a737bc 729 write_fifo((uint8_t *) &size, 1);
brunnobbco 0:561d07a737bc 730 } else {
brunnobbco 0:561d07a737bc 731 write_to_register(REG_PAYLOADLENGTH, size);
brunnobbco 0:561d07a737bc 732 }
brunnobbco 0:561d07a737bc 733
brunnobbco 0:561d07a737bc 734 if ((size > 0) && (size <= 64)) {
brunnobbco 0:561d07a737bc 735 _rf_settings.fsk_packet_handler.chunk_size = size;
brunnobbco 0:561d07a737bc 736 } else {
brunnobbco 0:561d07a737bc 737 memcpy(_data_buffer, buffer, size);
brunnobbco 0:561d07a737bc 738 _rf_settings.fsk_packet_handler.chunk_size = 32;
brunnobbco 0:561d07a737bc 739 }
brunnobbco 0:561d07a737bc 740
brunnobbco 0:561d07a737bc 741 // write payload buffer
brunnobbco 0:561d07a737bc 742 write_fifo(buffer, _rf_settings.fsk_packet_handler.chunk_size);
brunnobbco 0:561d07a737bc 743 _rf_settings.fsk_packet_handler.nb_bytes +=
brunnobbco 0:561d07a737bc 744 _rf_settings.fsk_packet_handler.chunk_size;
brunnobbco 0:561d07a737bc 745 tx_timeout = _rf_settings.fsk.tx_timeout;
brunnobbco 0:561d07a737bc 746
brunnobbco 0:561d07a737bc 747 break;
brunnobbco 0:561d07a737bc 748 case MODEM_LORA:
brunnobbco 0:561d07a737bc 749 if (_rf_settings.lora.iq_inverted == true) {
brunnobbco 0:561d07a737bc 750 write_to_register(REG_LR_INVERTIQ, ((read_register(REG_LR_INVERTIQ) &
brunnobbco 0:561d07a737bc 751 RFLR_INVERTIQ_TX_MASK &
brunnobbco 0:561d07a737bc 752 RFLR_INVERTIQ_RX_MASK) |
brunnobbco 0:561d07a737bc 753 RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_ON));
brunnobbco 0:561d07a737bc 754 write_to_register(REG_LR_INVERTIQ2, RFLR_INVERTIQ2_ON);
brunnobbco 0:561d07a737bc 755 } else {
brunnobbco 0:561d07a737bc 756 write_to_register(REG_LR_INVERTIQ, ((read_register(REG_LR_INVERTIQ) &
brunnobbco 0:561d07a737bc 757 RFLR_INVERTIQ_TX_MASK &
brunnobbco 0:561d07a737bc 758 RFLR_INVERTIQ_RX_MASK) |
brunnobbco 0:561d07a737bc 759 RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_OFF));
brunnobbco 0:561d07a737bc 760 write_to_register( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_OFF);
brunnobbco 0:561d07a737bc 761 }
brunnobbco 0:561d07a737bc 762
brunnobbco 0:561d07a737bc 763 _rf_settings.lora_packet_handler.size = size;
brunnobbco 0:561d07a737bc 764
brunnobbco 0:561d07a737bc 765 // Initializes the payload size
brunnobbco 0:561d07a737bc 766 write_to_register(REG_LR_PAYLOADLENGTH, size);
brunnobbco 0:561d07a737bc 767
brunnobbco 0:561d07a737bc 768 // Full buffer used for Tx
brunnobbco 0:561d07a737bc 769 write_to_register(REG_LR_FIFOTXBASEADDR, 0);
brunnobbco 0:561d07a737bc 770 write_to_register(REG_LR_FIFOADDRPTR, 0);
brunnobbco 0:561d07a737bc 771
brunnobbco 0:561d07a737bc 772 // FIFO operations can not take place in Sleep mode
brunnobbco 0:561d07a737bc 773 if ((read_register(REG_OPMODE) & ~RF_OPMODE_MASK) == RF_OPMODE_SLEEP) {
brunnobbco 0:561d07a737bc 774 standby();
brunnobbco 0:561d07a737bc 775 wait_ms(1);
brunnobbco 0:561d07a737bc 776 }
brunnobbco 0:561d07a737bc 777 // write payload buffer
brunnobbco 0:561d07a737bc 778 write_fifo(buffer, size);
brunnobbco 0:561d07a737bc 779 tx_timeout = _rf_settings.lora.tx_timeout;
brunnobbco 0:561d07a737bc 780
brunnobbco 0:561d07a737bc 781 break;
brunnobbco 0:561d07a737bc 782 }
brunnobbco 0:561d07a737bc 783
brunnobbco 0:561d07a737bc 784 // transmit
brunnobbco 0:561d07a737bc 785 transmit(tx_timeout);
brunnobbco 0:561d07a737bc 786 }
brunnobbco 0:561d07a737bc 787
brunnobbco 0:561d07a737bc 788 /**
brunnobbco 0:561d07a737bc 789 * Actual TX - Transmit routine
brunnobbco 0:561d07a737bc 790 *
brunnobbco 0:561d07a737bc 791 * A DIO0 interrupt let the state machine know that a a packet is
brunnobbco 0:561d07a737bc 792 * successfully sent, otherwise a TxTimeout is invoked.
brunnobbco 0:561d07a737bc 793 * TxTimeout should never happen in normal circumstances as the radio should
brunnobbco 0:561d07a737bc 794 * be able to send a packet out in the air no matter what.
brunnobbco 0:561d07a737bc 795 */
brunnobbco 0:561d07a737bc 796 void SX1272_LoRaRadio::transmit(uint32_t timeout)
brunnobbco 0:561d07a737bc 797 {
brunnobbco 0:561d07a737bc 798 switch (_rf_settings.modem) {
brunnobbco 0:561d07a737bc 799
brunnobbco 0:561d07a737bc 800 case MODEM_FSK:
brunnobbco 0:561d07a737bc 801 // DIO0=PacketSent
brunnobbco 0:561d07a737bc 802 // DIO1=FifoEmpty
brunnobbco 0:561d07a737bc 803 // DIO2=FifoFull
brunnobbco 0:561d07a737bc 804 // DIO3=FifoEmpty
brunnobbco 0:561d07a737bc 805 // DIO4=LowBat
brunnobbco 0:561d07a737bc 806 // DIO5=ModeReady
brunnobbco 0:561d07a737bc 807 write_to_register(REG_DIOMAPPING1,(read_register(REG_DIOMAPPING1) &
brunnobbco 0:561d07a737bc 808 RF_DIOMAPPING1_DIO0_MASK &
brunnobbco 0:561d07a737bc 809 RF_DIOMAPPING1_DIO1_MASK &
brunnobbco 0:561d07a737bc 810 RF_DIOMAPPING1_DIO2_MASK) |
brunnobbco 0:561d07a737bc 811 RF_DIOMAPPING1_DIO1_01);
brunnobbco 0:561d07a737bc 812
brunnobbco 0:561d07a737bc 813 write_to_register(REG_DIOMAPPING2, (read_register(REG_DIOMAPPING2) &
brunnobbco 0:561d07a737bc 814 RF_DIOMAPPING2_DIO4_MASK &
brunnobbco 0:561d07a737bc 815 RF_DIOMAPPING2_MAP_MASK));
brunnobbco 0:561d07a737bc 816 _rf_settings.fsk_packet_handler.fifo_thresh =
brunnobbco 0:561d07a737bc 817 read_register(REG_FIFOTHRESH) & 0x3F;
brunnobbco 0:561d07a737bc 818
brunnobbco 0:561d07a737bc 819
brunnobbco 0:561d07a737bc 820 break;
brunnobbco 0:561d07a737bc 821
brunnobbco 0:561d07a737bc 822 case MODEM_LORA:
brunnobbco 0:561d07a737bc 823
brunnobbco 1:3bdd6f917bf5 824 if (_rf_settings.lora.freq_hop_on == true)
brunnobbco 1:3bdd6f917bf5 825 {
brunnobbco 0:561d07a737bc 826 write_to_register(REG_LR_IRQFLAGSMASK,
brunnobbco 0:561d07a737bc 827 RFLR_IRQFLAGS_RXTIMEOUT |
brunnobbco 0:561d07a737bc 828 RFLR_IRQFLAGS_RXDONE |
brunnobbco 0:561d07a737bc 829 RFLR_IRQFLAGS_PAYLOADCRCERROR |
brunnobbco 0:561d07a737bc 830 RFLR_IRQFLAGS_VALIDHEADER |
brunnobbco 0:561d07a737bc 831 RFLR_IRQFLAGS_CADDONE |
brunnobbco 0:561d07a737bc 832 RFLR_IRQFLAGS_CADDETECTED);
brunnobbco 0:561d07a737bc 833
brunnobbco 0:561d07a737bc 834 // DIO0=tx_done, DIO2=fhss_change_channel
brunnobbco 0:561d07a737bc 835
brunnobbco 0:561d07a737bc 836 write_to_register(REG_DIOMAPPING1, (read_register(REG_DIOMAPPING1) &
brunnobbco 0:561d07a737bc 837 RFLR_DIOMAPPING1_DIO0_MASK &
brunnobbco 0:561d07a737bc 838 RFLR_DIOMAPPING1_DIO2_MASK) |
brunnobbco 0:561d07a737bc 839 RFLR_DIOMAPPING1_DIO0_01 |
brunnobbco 0:561d07a737bc 840 RFLR_DIOMAPPING1_DIO2_01);
brunnobbco 1:3bdd6f917bf5 841 }
brunnobbco 1:3bdd6f917bf5 842 else
brunnobbco 1:3bdd6f917bf5 843 {
brunnobbco 0:561d07a737bc 844 write_to_register(REG_LR_IRQFLAGSMASK,
brunnobbco 0:561d07a737bc 845 RFLR_IRQFLAGS_RXTIMEOUT |
brunnobbco 0:561d07a737bc 846 RFLR_IRQFLAGS_RXDONE |
brunnobbco 0:561d07a737bc 847 RFLR_IRQFLAGS_PAYLOADCRCERROR |
brunnobbco 0:561d07a737bc 848 RFLR_IRQFLAGS_VALIDHEADER |
brunnobbco 0:561d07a737bc 849 RFLR_IRQFLAGS_CADDONE |
brunnobbco 0:561d07a737bc 850 RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL |
brunnobbco 0:561d07a737bc 851 RFLR_IRQFLAGS_CADDETECTED);
brunnobbco 0:561d07a737bc 852
brunnobbco 0:561d07a737bc 853 // DIO0=tx_done
brunnobbco 0:561d07a737bc 854 write_to_register(REG_DIOMAPPING1,(read_register(REG_DIOMAPPING1) &
brunnobbco 0:561d07a737bc 855 RFLR_DIOMAPPING1_DIO0_MASK) |
brunnobbco 0:561d07a737bc 856 RFLR_DIOMAPPING1_DIO0_01);
brunnobbco 0:561d07a737bc 857 }
brunnobbco 0:561d07a737bc 858
brunnobbco 0:561d07a737bc 859 break;
brunnobbco 0:561d07a737bc 860 }
brunnobbco 0:561d07a737bc 861
brunnobbco 0:561d07a737bc 862 _rf_settings.state = RF_TX_RUNNING;
brunnobbco 1:3bdd6f917bf5 863
brunnobbco 0:561d07a737bc 864 tx_timeout_timer.attach_us(callback(this, &SX1272_LoRaRadio::timeout_irq_isr),
brunnobbco 0:561d07a737bc 865 timeout * 1000);
brunnobbco 1:3bdd6f917bf5 866
brunnobbco 1:3bdd6f917bf5 867 if ((_rf_settings.modem == MODEM_LORA) && (_rf_settings.lora.freq_hop_on == true))
brunnobbco 1:3bdd6f917bf5 868 {
brunnobbco 1:3bdd6f917bf5 869 lora_hop_timer.attach_us(callback(this, &SX1272_LoRaRadio::lrhop_irq_isr), 1000);
brunnobbco 1:3bdd6f917bf5 870 }
brunnobbco 1:3bdd6f917bf5 871
brunnobbco 0:561d07a737bc 872 set_operation_mode(RF_OPMODE_TRANSMITTER);
brunnobbco 0:561d07a737bc 873 }
brunnobbco 0:561d07a737bc 874
brunnobbco 0:561d07a737bc 875 /**
brunnobbco 0:561d07a737bc 876 * Sets the radio module in receive mode
brunnobbco 0:561d07a737bc 877 *
brunnobbco 0:561d07a737bc 878 * A DIO4 interrupt let's the state machine know that a preamble is detected
brunnobbco 0:561d07a737bc 879 * and finally a DIO0 interrupt let's the state machine know that a packet is
brunnobbco 0:561d07a737bc 880 * ready to be read from the FIFO
brunnobbco 0:561d07a737bc 881 */
brunnobbco 0:561d07a737bc 882 void SX1272_LoRaRadio::receive(void)
brunnobbco 0:561d07a737bc 883 {
brunnobbco 0:561d07a737bc 884 switch (_rf_settings.modem) {
brunnobbco 0:561d07a737bc 885 case MODEM_FSK:
brunnobbco 0:561d07a737bc 886 // DIO0=PayloadReady
brunnobbco 0:561d07a737bc 887 // DIO1=FifoLevel
brunnobbco 0:561d07a737bc 888 // DIO2=RxTimeout
brunnobbco 0:561d07a737bc 889 // DIO3=FifoEmpty
brunnobbco 0:561d07a737bc 890 // DIO4=Preamble
brunnobbco 0:561d07a737bc 891 // DIO5=ModeReady
brunnobbco 0:561d07a737bc 892 write_to_register(REG_DIOMAPPING1, (read_register(REG_DIOMAPPING1) &
brunnobbco 0:561d07a737bc 893 RF_DIOMAPPING1_DIO0_MASK &
brunnobbco 0:561d07a737bc 894 RF_DIOMAPPING1_DIO1_MASK &
brunnobbco 0:561d07a737bc 895 RF_DIOMAPPING1_DIO2_MASK) |
brunnobbco 0:561d07a737bc 896 RF_DIOMAPPING1_DIO0_00 |
brunnobbco 0:561d07a737bc 897 RF_DIOMAPPING1_DIO1_00 |
brunnobbco 0:561d07a737bc 898 RF_DIOMAPPING1_DIO2_10);
brunnobbco 0:561d07a737bc 899
brunnobbco 0:561d07a737bc 900 write_to_register(REG_DIOMAPPING2, (read_register(REG_DIOMAPPING2) &
brunnobbco 0:561d07a737bc 901 RF_DIOMAPPING2_DIO4_MASK &
brunnobbco 0:561d07a737bc 902 RF_DIOMAPPING2_MAP_MASK) |
brunnobbco 0:561d07a737bc 903 RF_DIOMAPPING2_DIO4_11 |
brunnobbco 0:561d07a737bc 904 RF_DIOMAPPING2_MAP_PREAMBLEDETECT);
brunnobbco 0:561d07a737bc 905
brunnobbco 0:561d07a737bc 906 _rf_settings.fsk_packet_handler.fifo_thresh =
brunnobbco 0:561d07a737bc 907 read_register(REG_FIFOTHRESH) & 0x3F;
brunnobbco 0:561d07a737bc 908
brunnobbco 0:561d07a737bc 909 write_to_register(REG_RXCONFIG, RF_RXCONFIG_AFCAUTO_ON |
brunnobbco 0:561d07a737bc 910 RF_RXCONFIG_AGCAUTO_ON |
brunnobbco 0:561d07a737bc 911 RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT);
brunnobbco 0:561d07a737bc 912
brunnobbco 0:561d07a737bc 913 if (!_rf_settings.fsk.rx_continuous) {
brunnobbco 0:561d07a737bc 914 // the value for rx timeout in symbols cannot be more than 255
brunnobbco 0:561d07a737bc 915 // as the preamble length is fixed. We assert here for quick
brunnobbco 0:561d07a737bc 916 // diagnostics
brunnobbco 0:561d07a737bc 917 MBED_ASSERT(_rf_settings.fsk.rx_single_timeout <= 255);
brunnobbco 0:561d07a737bc 918 write_to_register(REG_RXTIMEOUT2, _rf_settings.fsk.rx_single_timeout);
brunnobbco 0:561d07a737bc 919 write_to_register(REG_RXTIMEOUT3, 0x00);
brunnobbco 0:561d07a737bc 920 write_to_register(REG_RXTIMEOUT1, 0x00);
brunnobbco 0:561d07a737bc 921 }
brunnobbco 0:561d07a737bc 922
brunnobbco 0:561d07a737bc 923 _rf_settings.fsk_packet_handler.preamble_detected = 0;
brunnobbco 0:561d07a737bc 924 _rf_settings.fsk_packet_handler.sync_word_detected = 0;
brunnobbco 0:561d07a737bc 925 _rf_settings.fsk_packet_handler.nb_bytes = 0;
brunnobbco 0:561d07a737bc 926 _rf_settings.fsk_packet_handler.size = 0;
brunnobbco 0:561d07a737bc 927
brunnobbco 0:561d07a737bc 928
brunnobbco 0:561d07a737bc 929 break;
brunnobbco 0:561d07a737bc 930
brunnobbco 0:561d07a737bc 931 case MODEM_LORA:
brunnobbco 0:561d07a737bc 932
brunnobbco 0:561d07a737bc 933 if (_rf_settings.lora.iq_inverted == true) {
brunnobbco 0:561d07a737bc 934 write_to_register(REG_LR_INVERTIQ, ((read_register(REG_LR_INVERTIQ) &
brunnobbco 0:561d07a737bc 935 RFLR_INVERTIQ_TX_MASK &
brunnobbco 0:561d07a737bc 936 RFLR_INVERTIQ_RX_MASK) |
brunnobbco 0:561d07a737bc 937 RFLR_INVERTIQ_RX_ON |
brunnobbco 0:561d07a737bc 938 RFLR_INVERTIQ_TX_OFF));
brunnobbco 0:561d07a737bc 939 write_to_register(REG_LR_INVERTIQ2, RFLR_INVERTIQ2_ON);
brunnobbco 0:561d07a737bc 940 } else {
brunnobbco 0:561d07a737bc 941 write_to_register(REG_LR_INVERTIQ, ((read_register(REG_LR_INVERTIQ) &
brunnobbco 0:561d07a737bc 942 RFLR_INVERTIQ_TX_MASK &
brunnobbco 0:561d07a737bc 943 RFLR_INVERTIQ_RX_MASK) |
brunnobbco 0:561d07a737bc 944 RFLR_INVERTIQ_RX_OFF |
brunnobbco 0:561d07a737bc 945 RFLR_INVERTIQ_TX_OFF));
brunnobbco 0:561d07a737bc 946 write_to_register( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_OFF);
brunnobbco 0:561d07a737bc 947 }
brunnobbco 0:561d07a737bc 948
brunnobbco 0:561d07a737bc 949 if (_rf_settings.lora.freq_hop_on == true) {
brunnobbco 0:561d07a737bc 950 write_to_register(REG_LR_IRQFLAGSMASK,
brunnobbco 0:561d07a737bc 951 RFLR_IRQFLAGS_VALIDHEADER |
brunnobbco 0:561d07a737bc 952 RFLR_IRQFLAGS_TXDONE |
brunnobbco 0:561d07a737bc 953 RFLR_IRQFLAGS_CADDONE |
brunnobbco 0:561d07a737bc 954 RFLR_IRQFLAGS_CADDETECTED);
brunnobbco 0:561d07a737bc 955
brunnobbco 0:561d07a737bc 956 // DIO0=rx_done, DIO2=fhss_change_channel
brunnobbco 0:561d07a737bc 957 write_to_register(REG_DIOMAPPING1, (read_register(REG_DIOMAPPING1) &
brunnobbco 0:561d07a737bc 958 RFLR_DIOMAPPING1_DIO0_MASK &
brunnobbco 0:561d07a737bc 959 RFLR_DIOMAPPING1_DIO2_MASK) |
brunnobbco 0:561d07a737bc 960 RFLR_DIOMAPPING1_DIO0_00 |
brunnobbco 0:561d07a737bc 961 RFLR_DIOMAPPING1_DIO2_00);
brunnobbco 0:561d07a737bc 962 } else {
brunnobbco 0:561d07a737bc 963 write_to_register(REG_LR_IRQFLAGSMASK,
brunnobbco 0:561d07a737bc 964 RFLR_IRQFLAGS_VALIDHEADER |
brunnobbco 0:561d07a737bc 965 RFLR_IRQFLAGS_TXDONE |
brunnobbco 0:561d07a737bc 966 RFLR_IRQFLAGS_CADDONE |
brunnobbco 0:561d07a737bc 967 RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL |
brunnobbco 0:561d07a737bc 968 RFLR_IRQFLAGS_CADDETECTED);
brunnobbco 0:561d07a737bc 969
brunnobbco 0:561d07a737bc 970 // DIO0=rx_done
brunnobbco 0:561d07a737bc 971 write_to_register(REG_DIOMAPPING1, (read_register(REG_DIOMAPPING1) &
brunnobbco 0:561d07a737bc 972 RFLR_DIOMAPPING1_DIO0_MASK) |
brunnobbco 0:561d07a737bc 973 RFLR_DIOMAPPING1_DIO0_00);
brunnobbco 0:561d07a737bc 974 }
brunnobbco 0:561d07a737bc 975
brunnobbco 0:561d07a737bc 976 write_to_register(REG_LR_FIFORXBASEADDR, 0);
brunnobbco 0:561d07a737bc 977 write_to_register(REG_LR_FIFOADDRPTR, 0);
brunnobbco 0:561d07a737bc 978
brunnobbco 0:561d07a737bc 979 break;
brunnobbco 0:561d07a737bc 980 }
brunnobbco 0:561d07a737bc 981
brunnobbco 0:561d07a737bc 982 memset(_data_buffer, 0, (size_t) MAX_DATA_BUFFER_SIZE_SX172);
brunnobbco 0:561d07a737bc 983
brunnobbco 0:561d07a737bc 984 _rf_settings.state = RF_RX_RUNNING;
brunnobbco 0:561d07a737bc 985
brunnobbco 0:561d07a737bc 986 if (_rf_settings.modem == MODEM_FSK) {
brunnobbco 0:561d07a737bc 987 set_operation_mode(RF_OPMODE_RECEIVER);
brunnobbco 0:561d07a737bc 988 return;
brunnobbco 0:561d07a737bc 989 }
brunnobbco 0:561d07a737bc 990
brunnobbco 0:561d07a737bc 991 // If mode is LoRa set mode
brunnobbco 0:561d07a737bc 992 if (_rf_settings.lora.rx_continuous == true) {
brunnobbco 0:561d07a737bc 993 set_operation_mode(RFLR_OPMODE_RECEIVER);
brunnobbco 0:561d07a737bc 994 }
brunnobbco 0:561d07a737bc 995 else
brunnobbco 0:561d07a737bc 996 {
brunnobbco 1:3bdd6f917bf5 997 set_operation_mode(RFLR_OPMODE_RECEIVER_SINGLE);
brunnobbco 0:561d07a737bc 998 rx_sync_timer.attach_us(callback(this, &SX1272_LoRaRadio::rxsync_irq_isr), 1000);
brunnobbco 1:3bdd6f917bf5 999 }
brunnobbco 1:3bdd6f917bf5 1000
brunnobbco 1:3bdd6f917bf5 1001 if (_rf_settings.lora.freq_hop_on == true)
brunnobbco 1:3bdd6f917bf5 1002 {
brunnobbco 1:3bdd6f917bf5 1003 lora_hop_timer.attach_us(callback(this, &SX1272_LoRaRadio::lrhop_irq_isr), 1000);
brunnobbco 0:561d07a737bc 1004 }
brunnobbco 0:561d07a737bc 1005 }
brunnobbco 0:561d07a737bc 1006
brunnobbco 0:561d07a737bc 1007 /**
brunnobbco 0:561d07a737bc 1008 * Puts a limit on the size of payload the module can handle
brunnobbco 0:561d07a737bc 1009 * By default it is MAX, i.e., 256 bytes
brunnobbco 0:561d07a737bc 1010 */
brunnobbco 0:561d07a737bc 1011 void SX1272_LoRaRadio::set_max_payload_length(radio_modems_t modem, uint8_t max)
brunnobbco 0:561d07a737bc 1012 {
brunnobbco 0:561d07a737bc 1013 set_modem(modem);
brunnobbco 0:561d07a737bc 1014
brunnobbco 0:561d07a737bc 1015 switch (modem) {
brunnobbco 0:561d07a737bc 1016 case MODEM_FSK:
brunnobbco 0:561d07a737bc 1017 if (_rf_settings.fsk.fix_len == false) {
brunnobbco 0:561d07a737bc 1018 write_to_register(REG_PAYLOADLENGTH, max);
brunnobbco 0:561d07a737bc 1019 }
brunnobbco 0:561d07a737bc 1020 break;
brunnobbco 0:561d07a737bc 1021 case MODEM_LORA:
brunnobbco 0:561d07a737bc 1022 write_to_register(REG_LR_PAYLOADMAXLENGTH, max);
brunnobbco 0:561d07a737bc 1023 break;
brunnobbco 0:561d07a737bc 1024 }
brunnobbco 0:561d07a737bc 1025 }
brunnobbco 0:561d07a737bc 1026
brunnobbco 0:561d07a737bc 1027 /**
brunnobbco 0:561d07a737bc 1028 * TODO: Making sure if this API is valid only for LoRa modulation ?
brunnobbco 0:561d07a737bc 1029 *
brunnobbco 0:561d07a737bc 1030 * Indicates if the node is part of a private or public network
brunnobbco 0:561d07a737bc 1031 */
brunnobbco 0:561d07a737bc 1032 void SX1272_LoRaRadio::set_public_network(bool enable)
brunnobbco 0:561d07a737bc 1033 {
brunnobbco 0:561d07a737bc 1034 set_modem(MODEM_LORA);
brunnobbco 0:561d07a737bc 1035
brunnobbco 0:561d07a737bc 1036 _rf_settings.lora.public_network = enable;
brunnobbco 0:561d07a737bc 1037 if (enable == true) {
brunnobbco 0:561d07a737bc 1038 // Change lora modem SyncWord
brunnobbco 0:561d07a737bc 1039 write_to_register(REG_LR_SYNCWORD, LORA_MAC_PUBLIC_SYNCWORD);
brunnobbco 0:561d07a737bc 1040 } else {
brunnobbco 0:561d07a737bc 1041 // Change lora modem SyncWord
brunnobbco 0:561d07a737bc 1042 write_to_register(REG_LR_SYNCWORD, LORA_MAC_PRIVATE_SYNCWORD);
brunnobbco 0:561d07a737bc 1043 }
brunnobbco 0:561d07a737bc 1044
brunnobbco 0:561d07a737bc 1045 }
brunnobbco 0:561d07a737bc 1046
brunnobbco 0:561d07a737bc 1047 /**
brunnobbco 0:561d07a737bc 1048 * Perform carrier sensing
brunnobbco 0:561d07a737bc 1049 *
brunnobbco 0:561d07a737bc 1050 * Checks for a certain time if the RSSI is above a given threshold.
brunnobbco 0:561d07a737bc 1051 * This threshold determines if there is already a transmission going on
brunnobbco 0:561d07a737bc 1052 * in the channel or not.
brunnobbco 0:561d07a737bc 1053 *
brunnobbco 0:561d07a737bc 1054 */
brunnobbco 0:561d07a737bc 1055 bool SX1272_LoRaRadio::perform_carrier_sense(radio_modems_t modem,
brunnobbco 0:561d07a737bc 1056 uint32_t freq,
brunnobbco 0:561d07a737bc 1057 int16_t rssi_threshold,
brunnobbco 0:561d07a737bc 1058 uint32_t max_carrier_sense_time)
brunnobbco 0:561d07a737bc 1059 {
brunnobbco 0:561d07a737bc 1060 bool status = true;
brunnobbco 0:561d07a737bc 1061 int16_t rssi = 0;
brunnobbco 0:561d07a737bc 1062
brunnobbco 0:561d07a737bc 1063 set_modem(modem);
brunnobbco 0:561d07a737bc 1064 set_channel(freq);
brunnobbco 0:561d07a737bc 1065 set_operation_mode(RF_OPMODE_RECEIVER);
brunnobbco 0:561d07a737bc 1066
brunnobbco 0:561d07a737bc 1067 // hold on a bit, radio turn-around time
brunnobbco 0:561d07a737bc 1068 wait_ms(1);
brunnobbco 0:561d07a737bc 1069
brunnobbco 0:561d07a737bc 1070 Timer elapsed_time;
brunnobbco 0:561d07a737bc 1071 elapsed_time.start();
brunnobbco 0:561d07a737bc 1072
brunnobbco 0:561d07a737bc 1073 // Perform carrier sense for maxCarrierSenseTime
brunnobbco 0:561d07a737bc 1074 while (elapsed_time.read_ms() < (int)max_carrier_sense_time) {
brunnobbco 0:561d07a737bc 1075 rssi = get_rssi(modem);
brunnobbco 0:561d07a737bc 1076
brunnobbco 0:561d07a737bc 1077 if (rssi > rssi_threshold) {
brunnobbco 0:561d07a737bc 1078 status = false;
brunnobbco 0:561d07a737bc 1079 break;
brunnobbco 0:561d07a737bc 1080 }
brunnobbco 0:561d07a737bc 1081 }
brunnobbco 0:561d07a737bc 1082
brunnobbco 0:561d07a737bc 1083 sleep();
brunnobbco 0:561d07a737bc 1084 return status;
brunnobbco 0:561d07a737bc 1085 }
brunnobbco 0:561d07a737bc 1086
brunnobbco 0:561d07a737bc 1087 /**
brunnobbco 0:561d07a737bc 1088 * Channel Activity detection (can be done only in LoRa mode)
brunnobbco 0:561d07a737bc 1089 *
brunnobbco 0:561d07a737bc 1090 * If any activity on the channel is detected, an interrupt is asserted on
brunnobbco 0:561d07a737bc 1091 * DIO3. A callback will be generated to the stack/application upon the
brunnobbco 0:561d07a737bc 1092 * assertion of DIO3.
brunnobbco 0:561d07a737bc 1093 */
brunnobbco 0:561d07a737bc 1094 void SX1272_LoRaRadio::start_cad()
brunnobbco 0:561d07a737bc 1095 {
brunnobbco 0:561d07a737bc 1096 uint8_t reg_val;
brunnobbco 0:561d07a737bc 1097
brunnobbco 0:561d07a737bc 1098 switch (_rf_settings.modem) {
brunnobbco 0:561d07a737bc 1099 case MODEM_FSK:
brunnobbco 0:561d07a737bc 1100 break;
brunnobbco 0:561d07a737bc 1101 case MODEM_LORA:
brunnobbco 0:561d07a737bc 1102 write_to_register(REG_LR_IRQFLAGSMASK,
brunnobbco 0:561d07a737bc 1103 RFLR_IRQFLAGS_RXTIMEOUT |
brunnobbco 0:561d07a737bc 1104 RFLR_IRQFLAGS_RXDONE |
brunnobbco 0:561d07a737bc 1105 RFLR_IRQFLAGS_PAYLOADCRCERROR |
brunnobbco 0:561d07a737bc 1106 RFLR_IRQFLAGS_VALIDHEADER |
brunnobbco 0:561d07a737bc 1107 RFLR_IRQFLAGS_TXDONE |
brunnobbco 0:561d07a737bc 1108 RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL);
brunnobbco 0:561d07a737bc 1109
brunnobbco 0:561d07a737bc 1110 // DIO3=CADDone
brunnobbco 0:561d07a737bc 1111 reg_val = read_register(REG_DIOMAPPING1);
brunnobbco 0:561d07a737bc 1112 write_to_register(REG_DIOMAPPING1, (reg_val &
brunnobbco 0:561d07a737bc 1113 RFLR_DIOMAPPING1_DIO3_MASK) |
brunnobbco 0:561d07a737bc 1114 RFLR_DIOMAPPING1_DIO3_00);
brunnobbco 0:561d07a737bc 1115
brunnobbco 0:561d07a737bc 1116 set_operation_mode(RFLR_OPMODE_CAD);
brunnobbco 0:561d07a737bc 1117 _rf_settings.state = RF_CAD;
brunnobbco 1:3bdd6f917bf5 1118 lora_cad_timer.attach_us(callback(this, &SX1272_LoRaRadio::lrcad_irq_isr), 1000);
brunnobbco 0:561d07a737bc 1119 break;
brunnobbco 0:561d07a737bc 1120 default:
brunnobbco 0:561d07a737bc 1121 break;
brunnobbco 0:561d07a737bc 1122 }
brunnobbco 0:561d07a737bc 1123 }
brunnobbco 0:561d07a737bc 1124
brunnobbco 0:561d07a737bc 1125 /**
brunnobbco 0:561d07a737bc 1126 * Set transmission in continuous wave mode
brunnobbco 0:561d07a737bc 1127 */
brunnobbco 0:561d07a737bc 1128 void SX1272_LoRaRadio::set_tx_continuous_wave(uint32_t freq, int8_t power,
brunnobbco 0:561d07a737bc 1129 uint16_t time)
brunnobbco 0:561d07a737bc 1130 {
brunnobbco 0:561d07a737bc 1131 uint8_t reg_val;
brunnobbco 0:561d07a737bc 1132
brunnobbco 0:561d07a737bc 1133 set_channel(freq);
brunnobbco 0:561d07a737bc 1134 set_tx_config(MODEM_FSK, power, 0, 0, 4800, 0, 5, false, false, 0, 0, 0, time * 1000);
brunnobbco 0:561d07a737bc 1135 reg_val = read_register(REG_PACKETCONFIG2);
brunnobbco 0:561d07a737bc 1136
brunnobbco 0:561d07a737bc 1137 write_to_register( REG_PACKETCONFIG2, (reg_val & RF_PACKETCONFIG2_DATAMODE_MASK ) );
brunnobbco 0:561d07a737bc 1138 // Disable radio interrupts
brunnobbco 0:561d07a737bc 1139 write_to_register( REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_11 | RF_DIOMAPPING1_DIO1_11 );
brunnobbco 0:561d07a737bc 1140 write_to_register( REG_DIOMAPPING2, RF_DIOMAPPING2_DIO4_10 | RF_DIOMAPPING2_DIO5_10 );
brunnobbco 0:561d07a737bc 1141
brunnobbco 0:561d07a737bc 1142 _rf_settings.state = RF_TX_RUNNING;
brunnobbco 0:561d07a737bc 1143 tx_timeout_timer.attach_us(callback(this, &SX1272_LoRaRadio::timeout_irq_isr), time * 1000000);
brunnobbco 0:561d07a737bc 1144 set_operation_mode(RF_OPMODE_TRANSMITTER);
brunnobbco 0:561d07a737bc 1145 }
brunnobbco 0:561d07a737bc 1146
brunnobbco 0:561d07a737bc 1147 /**
brunnobbco 0:561d07a737bc 1148 * Put radio in Standby mode
brunnobbco 0:561d07a737bc 1149 */
brunnobbco 0:561d07a737bc 1150 void SX1272_LoRaRadio::standby( void )
brunnobbco 0:561d07a737bc 1151 {
brunnobbco 0:561d07a737bc 1152 tx_timeout_timer.detach();
brunnobbco 0:561d07a737bc 1153 rx_sync_timer.detach();
brunnobbco 1:3bdd6f917bf5 1154 lora_cad_timer.detach();
brunnobbco 1:3bdd6f917bf5 1155 lora_hop_timer.detach();
brunnobbco 0:561d07a737bc 1156 set_operation_mode(RF_OPMODE_STANDBY);
brunnobbco 0:561d07a737bc 1157 _rf_settings.state = RF_IDLE;
brunnobbco 0:561d07a737bc 1158 }
brunnobbco 0:561d07a737bc 1159
brunnobbco 0:561d07a737bc 1160 /**
brunnobbco 0:561d07a737bc 1161 * Generates 32 bit random number based upon RSSI monitoring
brunnobbco 0:561d07a737bc 1162 * Used for various calculation by the stack for example dev nonce
brunnobbco 0:561d07a737bc 1163 *
brunnobbco 0:561d07a737bc 1164 * When this API is used modem is set in LoRa mode and all interrupts are
brunnobbco 0:561d07a737bc 1165 * masked. If the user had been using FSK mode, it should be noted that a
brunnobbco 0:561d07a737bc 1166 * change of mode is required again because the registers have changed.
brunnobbco 0:561d07a737bc 1167 * In addition to that RX and TX configuration APIs should be called again in
brunnobbco 0:561d07a737bc 1168 * order to have correct desires setup.
brunnobbco 0:561d07a737bc 1169 */
brunnobbco 0:561d07a737bc 1170 uint32_t SX1272_LoRaRadio::random()
brunnobbco 0:561d07a737bc 1171 {
brunnobbco 0:561d07a737bc 1172 uint8_t i;
brunnobbco 0:561d07a737bc 1173 uint32_t rnd = 0;
brunnobbco 0:561d07a737bc 1174
brunnobbco 0:561d07a737bc 1175 // Set LoRa modem ON
brunnobbco 0:561d07a737bc 1176 set_modem(MODEM_LORA);
brunnobbco 0:561d07a737bc 1177
brunnobbco 0:561d07a737bc 1178 // Disable LoRa modem interrupts, i.e., mask all interrupts
brunnobbco 0:561d07a737bc 1179 write_to_register(REG_LR_IRQFLAGSMASK, RFLR_IRQFLAGS_RXTIMEOUT | RFLR_IRQFLAGS_RXDONE
brunnobbco 0:561d07a737bc 1180 | RFLR_IRQFLAGS_PAYLOADCRCERROR | RFLR_IRQFLAGS_VALIDHEADER
brunnobbco 0:561d07a737bc 1181 | RFLR_IRQFLAGS_TXDONE | RFLR_IRQFLAGS_CADDONE
brunnobbco 0:561d07a737bc 1182 | RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL | RFLR_IRQFLAGS_CADDETECTED);
brunnobbco 0:561d07a737bc 1183
brunnobbco 0:561d07a737bc 1184 // Set radio in continuous reception
brunnobbco 0:561d07a737bc 1185 set_operation_mode(RF_OPMODE_RECEIVER);
brunnobbco 0:561d07a737bc 1186
brunnobbco 0:561d07a737bc 1187 for (i = 0; i < 32; i++) {
brunnobbco 0:561d07a737bc 1188 wait_ms(1);
brunnobbco 0:561d07a737bc 1189 // Unfiltered RSSI value reading. Only takes the LSB value
brunnobbco 0:561d07a737bc 1190 rnd |= ((uint32_t) read_register(REG_LR_RSSIWIDEBAND) & 0x01) << i;
brunnobbco 0:561d07a737bc 1191 }
brunnobbco 0:561d07a737bc 1192
brunnobbco 0:561d07a737bc 1193 sleep();
brunnobbco 0:561d07a737bc 1194
brunnobbco 0:561d07a737bc 1195 return rnd;
brunnobbco 0:561d07a737bc 1196 }
brunnobbco 0:561d07a737bc 1197
brunnobbco 0:561d07a737bc 1198
brunnobbco 0:561d07a737bc 1199 /*****************************************************************************
brunnobbco 0:561d07a737bc 1200 * Private APIs *
brunnobbco 0:561d07a737bc 1201 ****************************************************************************/
brunnobbco 0:561d07a737bc 1202 #ifdef MBED_CONF_RTOS_PRESENT
brunnobbco 0:561d07a737bc 1203 /**
brunnobbco 0:561d07a737bc 1204 * Thread task handling IRQs
brunnobbco 0:561d07a737bc 1205 */
brunnobbco 0:561d07a737bc 1206 void SX1272_LoRaRadio::rf_irq_task(void)
brunnobbco 0:561d07a737bc 1207 {
brunnobbco 0:561d07a737bc 1208 for (;;) {
brunnobbco 0:561d07a737bc 1209 uint32_t flags = ThisThread::flags_wait_any(0x7FFFFFFF);
brunnobbco 0:561d07a737bc 1210
brunnobbco 0:561d07a737bc 1211 lock();
brunnobbco 0:561d07a737bc 1212 if (flags & SIG_DIO0) {
brunnobbco 0:561d07a737bc 1213 handle_dio0_irq();
brunnobbco 0:561d07a737bc 1214 }
brunnobbco 0:561d07a737bc 1215 if (flags & SIG_DIO1) {
brunnobbco 0:561d07a737bc 1216 handle_dio1_irq();
brunnobbco 0:561d07a737bc 1217 }
brunnobbco 0:561d07a737bc 1218 if (flags & SIG_DIO2) {
brunnobbco 0:561d07a737bc 1219 handle_dio2_irq();
brunnobbco 0:561d07a737bc 1220 }
brunnobbco 1:3bdd6f917bf5 1221 if (flags & SIG_LRHOP) {
brunnobbco 1:3bdd6f917bf5 1222 handle_lrhop_irq();
brunnobbco 0:561d07a737bc 1223 }
brunnobbco 1:3bdd6f917bf5 1224 if (flags & SIG_LRCAD) {
brunnobbco 1:3bdd6f917bf5 1225 handle_lrcad_irq();
brunnobbco 0:561d07a737bc 1226 }
brunnobbco 0:561d07a737bc 1227 if (flags & SIG_TIMOUT) {
brunnobbco 0:561d07a737bc 1228 handle_timeout_irq();
brunnobbco 0:561d07a737bc 1229 }
brunnobbco 0:561d07a737bc 1230 if (flags & SIG_RXSYNC) {
brunnobbco 0:561d07a737bc 1231 handle_rxsync_irq();
brunnobbco 0:561d07a737bc 1232 }
brunnobbco 0:561d07a737bc 1233 unlock();
brunnobbco 0:561d07a737bc 1234 }
brunnobbco 0:561d07a737bc 1235 }
brunnobbco 0:561d07a737bc 1236 #endif
brunnobbco 0:561d07a737bc 1237
brunnobbco 0:561d07a737bc 1238 /**
brunnobbco 0:561d07a737bc 1239 * Writes a single byte to a given register
brunnobbco 0:561d07a737bc 1240 */
brunnobbco 0:561d07a737bc 1241 void SX1272_LoRaRadio::write_to_register(uint8_t addr, uint8_t data)
brunnobbco 0:561d07a737bc 1242 {
brunnobbco 0:561d07a737bc 1243 write_to_register(addr, &data, 1);
brunnobbco 0:561d07a737bc 1244 }
brunnobbco 0:561d07a737bc 1245
brunnobbco 0:561d07a737bc 1246 /**
brunnobbco 0:561d07a737bc 1247 * Writes multiple bytes to a given register
brunnobbco 0:561d07a737bc 1248 */
brunnobbco 0:561d07a737bc 1249 void SX1272_LoRaRadio::write_to_register(uint8_t addr, uint8_t *data, uint8_t size)
brunnobbco 0:561d07a737bc 1250 {
brunnobbco 0:561d07a737bc 1251 // set chip-select low
brunnobbco 0:561d07a737bc 1252 _chip_select = 0;
brunnobbco 0:561d07a737bc 1253
brunnobbco 0:561d07a737bc 1254 // set write command
brunnobbco 0:561d07a737bc 1255 _spi.write(addr | SPI_WRITE_CMD);
brunnobbco 0:561d07a737bc 1256
brunnobbco 0:561d07a737bc 1257 // write data
brunnobbco 0:561d07a737bc 1258 for (uint8_t i = 0; i < size; i++) {
brunnobbco 0:561d07a737bc 1259 _spi.write(data[i]);
brunnobbco 0:561d07a737bc 1260 }
brunnobbco 0:561d07a737bc 1261
brunnobbco 0:561d07a737bc 1262 // set chip-select high
brunnobbco 0:561d07a737bc 1263 _chip_select = 1;
brunnobbco 0:561d07a737bc 1264 }
brunnobbco 0:561d07a737bc 1265
brunnobbco 0:561d07a737bc 1266 /**
brunnobbco 0:561d07a737bc 1267 * Reads the value of a single register
brunnobbco 0:561d07a737bc 1268 */
brunnobbco 0:561d07a737bc 1269 uint8_t SX1272_LoRaRadio::read_register(uint8_t addr)
brunnobbco 0:561d07a737bc 1270 {
brunnobbco 0:561d07a737bc 1271 uint8_t data;
brunnobbco 0:561d07a737bc 1272 read_register(addr, &data, 1);
brunnobbco 0:561d07a737bc 1273 return data;
brunnobbco 0:561d07a737bc 1274 }
brunnobbco 0:561d07a737bc 1275
brunnobbco 0:561d07a737bc 1276 /**
brunnobbco 0:561d07a737bc 1277 * Reads multiple values from a given register
brunnobbco 0:561d07a737bc 1278 */
brunnobbco 0:561d07a737bc 1279 void SX1272_LoRaRadio::read_register(uint8_t addr, uint8_t *buffer, uint8_t size)
brunnobbco 0:561d07a737bc 1280 {
brunnobbco 0:561d07a737bc 1281 // set chip-select low
brunnobbco 0:561d07a737bc 1282 _chip_select = 0;
brunnobbco 0:561d07a737bc 1283
brunnobbco 0:561d07a737bc 1284 // set read command
brunnobbco 0:561d07a737bc 1285 _spi.write(addr & SPI_READ_CMD);
brunnobbco 0:561d07a737bc 1286
brunnobbco 0:561d07a737bc 1287 // read buffers
brunnobbco 0:561d07a737bc 1288 for (uint8_t i = 0; i < size; i++) {
brunnobbco 0:561d07a737bc 1289 buffer[i] = _spi.write(0);
brunnobbco 0:561d07a737bc 1290 }
brunnobbco 0:561d07a737bc 1291
brunnobbco 0:561d07a737bc 1292 // set chip-select high
brunnobbco 0:561d07a737bc 1293 _chip_select = 1;
brunnobbco 0:561d07a737bc 1294 }
brunnobbco 0:561d07a737bc 1295
brunnobbco 0:561d07a737bc 1296 /**
brunnobbco 0:561d07a737bc 1297 * Writes to FIIO provided by the chip
brunnobbco 0:561d07a737bc 1298 */
brunnobbco 0:561d07a737bc 1299 void SX1272_LoRaRadio::write_fifo(uint8_t *buffer, uint8_t size)
brunnobbco 0:561d07a737bc 1300 {
brunnobbco 0:561d07a737bc 1301 write_to_register(0, buffer, size);
brunnobbco 0:561d07a737bc 1302 }
brunnobbco 0:561d07a737bc 1303
brunnobbco 0:561d07a737bc 1304 /**
brunnobbco 0:561d07a737bc 1305 * Reads from the FIFO provided by the chip
brunnobbco 0:561d07a737bc 1306 */
brunnobbco 0:561d07a737bc 1307 void SX1272_LoRaRadio::read_fifo(uint8_t *buffer, uint8_t size)
brunnobbco 0:561d07a737bc 1308 {
brunnobbco 0:561d07a737bc 1309 read_register(0, buffer, size);
brunnobbco 0:561d07a737bc 1310 }
brunnobbco 0:561d07a737bc 1311
brunnobbco 0:561d07a737bc 1312 /**
brunnobbco 0:561d07a737bc 1313 * Gets FSK bandwidth values
brunnobbco 0:561d07a737bc 1314 *
brunnobbco 0:561d07a737bc 1315 * Gives either normal bandwidths or bandwidths for
brunnobbco 0:561d07a737bc 1316 * AFC (auto frequency correction)
brunnobbco 0:561d07a737bc 1317 */
brunnobbco 0:561d07a737bc 1318 uint8_t SX1272_LoRaRadio::get_fsk_bw_reg_val(uint32_t bandwidth)
brunnobbco 0:561d07a737bc 1319 {
brunnobbco 0:561d07a737bc 1320 uint8_t i;
brunnobbco 0:561d07a737bc 1321
brunnobbco 0:561d07a737bc 1322 for (i = 0; i < (sizeof(fsk_bandwidths) / sizeof(fsk_bw_t)) - 1; i++) {
brunnobbco 0:561d07a737bc 1323 if ((bandwidth >= fsk_bandwidths[i].bandwidth)
brunnobbco 0:561d07a737bc 1324 && (bandwidth < fsk_bandwidths[i + 1].bandwidth)) {
brunnobbco 0:561d07a737bc 1325 return fsk_bandwidths[i].register_value;
brunnobbco 0:561d07a737bc 1326 }
brunnobbco 0:561d07a737bc 1327 }
brunnobbco 0:561d07a737bc 1328 // ERROR: Value not found
brunnobbco 0:561d07a737bc 1329 // This should never happen
brunnobbco 0:561d07a737bc 1330 while (1);
brunnobbco 0:561d07a737bc 1331 }
brunnobbco 0:561d07a737bc 1332
brunnobbco 0:561d07a737bc 1333 /**
brunnobbco 0:561d07a737bc 1334 * Sets the radio modules to default position (off)
brunnobbco 0:561d07a737bc 1335 *
brunnobbco 0:561d07a737bc 1336 * Historically they were being called as Antenna switches, so we kept the name.
brunnobbco 0:561d07a737bc 1337 * In essence these are control latches over duplexer which either let
brunnobbco 0:561d07a737bc 1338 * TX submodule or RX submodule circuitry enabled at a time.
brunnobbco 0:561d07a737bc 1339 */
brunnobbco 0:561d07a737bc 1340 void SX1272_LoRaRadio::default_antenna_switch_ctrls()
brunnobbco 0:561d07a737bc 1341 {
brunnobbco 0:561d07a737bc 1342 if (_rf_ctrls.pwr_amp_ctl != NC) {
brunnobbco 0:561d07a737bc 1343 _pwr_amp_ctl = 0;
brunnobbco 0:561d07a737bc 1344 }
brunnobbco 0:561d07a737bc 1345
brunnobbco 5:3da1a3924c65 1346 if (_rf_ctrls.rf_switch_ctl1 != NC) {
brunnobbco 0:561d07a737bc 1347 _rf_switch_ctl1 = 0;
brunnobbco 5:3da1a3924c65 1348 }
brunnobbco 5:3da1a3924c65 1349
brunnobbco 5:3da1a3924c65 1350 if (_rf_ctrls.rf_switch_ctl2 != NC) {
brunnobbco 0:561d07a737bc 1351 _rf_switch_ctl2 = 0;
brunnobbco 0:561d07a737bc 1352 }
brunnobbco 0:561d07a737bc 1353
brunnobbco 0:561d07a737bc 1354 if (_rf_ctrls.txctl != NC && _rf_ctrls.rxctl != NC) {
brunnobbco 0:561d07a737bc 1355 _txctl = 0;
brunnobbco 0:561d07a737bc 1356 _rxctl = 0;
brunnobbco 0:561d07a737bc 1357 }
brunnobbco 0:561d07a737bc 1358 }
brunnobbco 0:561d07a737bc 1359
brunnobbco 0:561d07a737bc 1360 /**
brunnobbco 0:561d07a737bc 1361 * Gets the power amplifier configuration register
brunnobbco 0:561d07a737bc 1362 */
brunnobbco 0:561d07a737bc 1363 uint8_t SX1272_LoRaRadio::get_pa_conf_reg()
brunnobbco 0:561d07a737bc 1364 {
brunnobbco 3:bca9a8ee555d 1365 if (radio_variant == SX1272PABOOST) {
brunnobbco 0:561d07a737bc 1366 return RF_PACONFIG_PASELECT_PABOOST;
brunnobbco 3:bca9a8ee555d 1367 }
brunnobbco 3:bca9a8ee555d 1368 else {
brunnobbco 0:561d07a737bc 1369 return RF_PACONFIG_PASELECT_RFO;
brunnobbco 0:561d07a737bc 1370 }
brunnobbco 0:561d07a737bc 1371 }
brunnobbco 0:561d07a737bc 1372
brunnobbco 0:561d07a737bc 1373 /**
brunnobbco 0:561d07a737bc 1374 * Get RSSI from the module
brunnobbco 0:561d07a737bc 1375 */
brunnobbco 0:561d07a737bc 1376 int16_t SX1272_LoRaRadio::get_rssi(radio_modems_t modem)
brunnobbco 0:561d07a737bc 1377 {
brunnobbco 0:561d07a737bc 1378 int16_t rssi = 0;
brunnobbco 0:561d07a737bc 1379
brunnobbco 0:561d07a737bc 1380 switch( modem )
brunnobbco 0:561d07a737bc 1381 {
brunnobbco 0:561d07a737bc 1382 case MODEM_FSK:
brunnobbco 0:561d07a737bc 1383 rssi = -(read_register(REG_RSSIVALUE) >> 1 );
brunnobbco 0:561d07a737bc 1384 break;
brunnobbco 0:561d07a737bc 1385 case MODEM_LORA:
brunnobbco 0:561d07a737bc 1386 rssi = RSSI_OFFSET + read_register(REG_LR_RSSIVALUE);
brunnobbco 0:561d07a737bc 1387 break;
brunnobbco 0:561d07a737bc 1388 default:
brunnobbco 0:561d07a737bc 1389 rssi = -1;
brunnobbco 0:561d07a737bc 1390 break;
brunnobbco 0:561d07a737bc 1391 }
brunnobbco 0:561d07a737bc 1392 return rssi;
brunnobbco 0:561d07a737bc 1393 }
brunnobbco 0:561d07a737bc 1394
brunnobbco 0:561d07a737bc 1395 /**
brunnobbco 0:561d07a737bc 1396 * Sets the transmit power for the module
brunnobbco 0:561d07a737bc 1397 */
brunnobbco 0:561d07a737bc 1398 void SX1272_LoRaRadio::set_rf_tx_power(int8_t power)
brunnobbco 0:561d07a737bc 1399 {
brunnobbco 0:561d07a737bc 1400 uint8_t pa_config = 0;
brunnobbco 0:561d07a737bc 1401 uint8_t pa_dac = 0;
brunnobbco 0:561d07a737bc 1402
brunnobbco 0:561d07a737bc 1403 pa_config = read_register(REG_PACONFIG);
brunnobbco 0:561d07a737bc 1404 pa_dac = read_register(REG_PADAC);
brunnobbco 0:561d07a737bc 1405 pa_config = (pa_config & RF_PACONFIG_PASELECT_MASK) | get_pa_conf_reg();
brunnobbco 0:561d07a737bc 1406
brunnobbco 0:561d07a737bc 1407 if ((pa_config & RF_PACONFIG_PASELECT_PABOOST)
brunnobbco 0:561d07a737bc 1408 == RF_PACONFIG_PASELECT_PABOOST) {
brunnobbco 0:561d07a737bc 1409 if (power > 17) {
brunnobbco 0:561d07a737bc 1410 pa_dac = (pa_dac & RF_PADAC_20DBM_MASK) | RF_PADAC_20DBM_ON;
brunnobbco 0:561d07a737bc 1411 } else {
brunnobbco 0:561d07a737bc 1412 pa_dac = (pa_dac & RF_PADAC_20DBM_MASK) | RF_PADAC_20DBM_OFF;
brunnobbco 0:561d07a737bc 1413 }
brunnobbco 0:561d07a737bc 1414 if ((pa_dac & RF_PADAC_20DBM_ON) == RF_PADAC_20DBM_ON) {
brunnobbco 0:561d07a737bc 1415 if (power < 5) {
brunnobbco 0:561d07a737bc 1416 power = 5;
brunnobbco 0:561d07a737bc 1417 }
brunnobbco 0:561d07a737bc 1418 if (power > 20) {
brunnobbco 0:561d07a737bc 1419 power = 20;
brunnobbco 0:561d07a737bc 1420 }
brunnobbco 0:561d07a737bc 1421 pa_config = (pa_config & RFLR_PACONFIG_OUTPUTPOWER_MASK)
brunnobbco 0:561d07a737bc 1422 | (uint8_t) ((uint16_t) (power - 5) & 0x0F);
brunnobbco 0:561d07a737bc 1423 } else {
brunnobbco 0:561d07a737bc 1424 if (power < 2) {
brunnobbco 0:561d07a737bc 1425 power = 2;
brunnobbco 0:561d07a737bc 1426 }
brunnobbco 0:561d07a737bc 1427 if (power > 17) {
brunnobbco 0:561d07a737bc 1428 power = 17;
brunnobbco 0:561d07a737bc 1429 }
brunnobbco 0:561d07a737bc 1430 pa_config = (pa_config & RFLR_PACONFIG_OUTPUTPOWER_MASK)
brunnobbco 0:561d07a737bc 1431 | (uint8_t) ((uint16_t) (power - 2) & 0x0F);
brunnobbco 0:561d07a737bc 1432 }
brunnobbco 0:561d07a737bc 1433 } else {
brunnobbco 0:561d07a737bc 1434 if (power < -1) {
brunnobbco 0:561d07a737bc 1435 power = -1;
brunnobbco 0:561d07a737bc 1436 }
brunnobbco 0:561d07a737bc 1437 if (power > 14) {
brunnobbco 0:561d07a737bc 1438 power = 14;
brunnobbco 0:561d07a737bc 1439 }
brunnobbco 0:561d07a737bc 1440 pa_config = (pa_config & RFLR_PACONFIG_OUTPUTPOWER_MASK)
brunnobbco 0:561d07a737bc 1441 | (uint8_t) ((uint16_t) (power + 1) & 0x0F);
brunnobbco 0:561d07a737bc 1442 }
brunnobbco 0:561d07a737bc 1443 write_to_register(REG_PACONFIG, pa_config);
brunnobbco 0:561d07a737bc 1444 write_to_register(REG_PADAC, pa_dac);
brunnobbco 0:561d07a737bc 1445 }
brunnobbco 0:561d07a737bc 1446
brunnobbco 0:561d07a737bc 1447 /**
brunnobbco 0:561d07a737bc 1448 * Sets the radio registers to defaults
brunnobbco 0:561d07a737bc 1449 */
brunnobbco 0:561d07a737bc 1450 void SX1272_LoRaRadio::setup_registers()
brunnobbco 0:561d07a737bc 1451 {
brunnobbco 0:561d07a737bc 1452 for (unsigned int i = 0; i < sizeof(radio_reg_init) / sizeof(radio_registers_t); i++) {
brunnobbco 0:561d07a737bc 1453 set_modem(radio_reg_init[i].modem);
brunnobbco 0:561d07a737bc 1454 write_to_register(radio_reg_init[i].addr, radio_reg_init[i].value);
brunnobbco 0:561d07a737bc 1455 }
brunnobbco 0:561d07a737bc 1456 }
brunnobbco 0:561d07a737bc 1457
brunnobbco 0:561d07a737bc 1458 /**
brunnobbco 0:561d07a737bc 1459 * Set the radio module variant
brunnobbco 0:561d07a737bc 1460 */
brunnobbco 0:561d07a737bc 1461 void SX1272_LoRaRadio::set_sx1272_variant_type()
brunnobbco 0:561d07a737bc 1462 {
brunnobbco 3:bca9a8ee555d 1463 radio_variant = MBED_CONF_SX1272_LORA_DRIVER_RADIO_VARIANT;
brunnobbco 0:561d07a737bc 1464 }
brunnobbco 0:561d07a737bc 1465
brunnobbco 0:561d07a737bc 1466 /**
brunnobbco 0:561d07a737bc 1467 * Sets up radio latch position according to the
brunnobbco 0:561d07a737bc 1468 * radio mode
brunnobbco 0:561d07a737bc 1469 */
brunnobbco 0:561d07a737bc 1470 void SX1272_LoRaRadio::set_antenna_switch(uint8_t mode)
brunnobbco 0:561d07a737bc 1471 {
brunnobbco 0:561d07a737bc 1472 // here we got to do ifdef for changing controls
brunnobbco 0:561d07a737bc 1473 // as some pins might be NC
brunnobbco 0:561d07a737bc 1474 switch (mode) {
brunnobbco 0:561d07a737bc 1475 case RFLR_OPMODE_TRANSMITTER:
brunnobbco 3:bca9a8ee555d 1476 if (radio_variant == SX1272PABOOST)
brunnobbco 3:bca9a8ee555d 1477 {
brunnobbco 0:561d07a737bc 1478 if ((read_register(REG_PACONFIG) & RF_PACONFIG_PASELECT_PABOOST)
brunnobbco 3:bca9a8ee555d 1479 == RF_PACONFIG_PASELECT_PABOOST)
brunnobbco 3:bca9a8ee555d 1480 {
brunnobbco 3:bca9a8ee555d 1481 if (_rf_ctrls.rf_switch_ctl1 != NC) {
brunnobbco 3:bca9a8ee555d 1482 _rf_switch_ctl1 = 1;
brunnobbco 3:bca9a8ee555d 1483 }
brunnobbco 3:bca9a8ee555d 1484 if (_rf_ctrls.rf_switch_ctl2 != NC) {
brunnobbco 3:bca9a8ee555d 1485 _rf_switch_ctl2 = 0;
brunnobbco 3:bca9a8ee555d 1486 }
brunnobbco 0:561d07a737bc 1487 }
brunnobbco 3:bca9a8ee555d 1488 else
brunnobbco 3:bca9a8ee555d 1489 {
brunnobbco 3:bca9a8ee555d 1490 if (_rf_ctrls.rf_switch_ctl1 != NC) {
brunnobbco 3:bca9a8ee555d 1491 _rf_switch_ctl1 = 0;
brunnobbco 3:bca9a8ee555d 1492 }
brunnobbco 3:bca9a8ee555d 1493 if (_rf_ctrls.rf_switch_ctl2 != NC) {
brunnobbco 3:bca9a8ee555d 1494 _rf_switch_ctl2 = 1;
brunnobbco 3:bca9a8ee555d 1495 }
brunnobbco 3:bca9a8ee555d 1496 }
brunnobbco 3:bca9a8ee555d 1497 }
brunnobbco 3:bca9a8ee555d 1498 if (_rf_ctrls.txctl != NC && _rf_ctrls.rxctl != NC)
brunnobbco 3:bca9a8ee555d 1499 {
brunnobbco 0:561d07a737bc 1500 _txctl = 1;
brunnobbco 0:561d07a737bc 1501 _rxctl = 0;
brunnobbco 3:bca9a8ee555d 1502 }
brunnobbco 3:bca9a8ee555d 1503 if (_rf_ctrls.ant_switch != NC) {
brunnobbco 0:561d07a737bc 1504 _ant_switch = 1;
brunnobbco 0:561d07a737bc 1505 }
brunnobbco 0:561d07a737bc 1506 break;
brunnobbco 3:bca9a8ee555d 1507
brunnobbco 0:561d07a737bc 1508 case RFLR_OPMODE_RECEIVER:
brunnobbco 0:561d07a737bc 1509 case RFLR_OPMODE_RECEIVER_SINGLE:
brunnobbco 0:561d07a737bc 1510 case RFLR_OPMODE_CAD:
brunnobbco 3:bca9a8ee555d 1511 if (_rf_ctrls.rf_switch_ctl1 != NC) {
brunnobbco 3:bca9a8ee555d 1512 _rf_switch_ctl1 = 0;
brunnobbco 3:bca9a8ee555d 1513 }
brunnobbco 3:bca9a8ee555d 1514 if (_rf_ctrls.rf_switch_ctl2 != NC) {
brunnobbco 3:bca9a8ee555d 1515 _rf_switch_ctl2 = 0;
brunnobbco 3:bca9a8ee555d 1516 }
brunnobbco 3:bca9a8ee555d 1517 if (_rf_ctrls.txctl != NC && _rf_ctrls.rxctl != NC) {
brunnobbco 0:561d07a737bc 1518 _txctl = 0;
brunnobbco 0:561d07a737bc 1519 _rxctl = 1;
brunnobbco 3:bca9a8ee555d 1520 }
brunnobbco 3:bca9a8ee555d 1521 if (_rf_ctrls.ant_switch != NC) {
brunnobbco 0:561d07a737bc 1522 _ant_switch = 0;
brunnobbco 0:561d07a737bc 1523 }
brunnobbco 0:561d07a737bc 1524 break;
brunnobbco 3:bca9a8ee555d 1525
brunnobbco 0:561d07a737bc 1526 default:
brunnobbco 3:bca9a8ee555d 1527 if (_rf_ctrls.rf_switch_ctl1 != NC) {
brunnobbco 0:561d07a737bc 1528 _rf_switch_ctl1 = 0;
brunnobbco 3:bca9a8ee555d 1529 }
brunnobbco 3:bca9a8ee555d 1530 if (_rf_ctrls.rf_switch_ctl2 != NC) {
brunnobbco 0:561d07a737bc 1531 _rf_switch_ctl2 = 0;
brunnobbco 3:bca9a8ee555d 1532 }
brunnobbco 3:bca9a8ee555d 1533 if (_rf_ctrls.txctl != NC && _rf_ctrls.rxctl != NC) {
brunnobbco 0:561d07a737bc 1534 _txctl = 0;
brunnobbco 0:561d07a737bc 1535 _rxctl = 0;
brunnobbco 3:bca9a8ee555d 1536 }
brunnobbco 3:bca9a8ee555d 1537 if (_rf_ctrls.ant_switch != NC) {
brunnobbco 0:561d07a737bc 1538 _ant_switch = 0;
brunnobbco 0:561d07a737bc 1539 }
brunnobbco 0:561d07a737bc 1540 break;
brunnobbco 0:561d07a737bc 1541 }
brunnobbco 0:561d07a737bc 1542 }
brunnobbco 0:561d07a737bc 1543
brunnobbco 0:561d07a737bc 1544 /**
brunnobbco 0:561d07a737bc 1545 * Sets up frequency for SPI module
brunnobbco 0:561d07a737bc 1546 * Reference DataSheet: 4.3 SPI Interface
brunnobbco 0:561d07a737bc 1547 */
brunnobbco 0:561d07a737bc 1548 void SX1272_LoRaRadio::setup_spi()
brunnobbco 0:561d07a737bc 1549 {
brunnobbco 0:561d07a737bc 1550 // SPI bus frequency
brunnobbco 0:561d07a737bc 1551 uint32_t spi_freq = SPI_FREQUENCY;
brunnobbco 0:561d07a737bc 1552
brunnobbco 0:561d07a737bc 1553 // Hold chip-select high
brunnobbco 0:561d07a737bc 1554 _chip_select = 1;
brunnobbco 0:561d07a737bc 1555 _spi.format(8, 0);
brunnobbco 0:561d07a737bc 1556
brunnobbco 0:561d07a737bc 1557 #if defined (TARGET_KL25Z)
brunnobbco 0:561d07a737bc 1558 //bus-clock frequency is halved -> double the SPI frequency to compensate
brunnobbco 0:561d07a737bc 1559 _spi.frequency(spi_freq * 2);
brunnobbco 0:561d07a737bc 1560 #else
brunnobbco 0:561d07a737bc 1561 // otherwise use default SPI frequency which is 8 MHz
brunnobbco 0:561d07a737bc 1562 _spi.frequency(spi_freq);
brunnobbco 0:561d07a737bc 1563 #endif
brunnobbco 0:561d07a737bc 1564 // 100 us wait to settle down
brunnobbco 0:561d07a737bc 1565 wait(0.1);
brunnobbco 0:561d07a737bc 1566 }
brunnobbco 0:561d07a737bc 1567
brunnobbco 0:561d07a737bc 1568 /**
brunnobbco 0:561d07a737bc 1569 * Attaches ISRs to interrupt pins
brunnobbco 0:561d07a737bc 1570 */
brunnobbco 0:561d07a737bc 1571 void SX1272_LoRaRadio::setup_interrupts()
brunnobbco 0:561d07a737bc 1572 {
brunnobbco 0:561d07a737bc 1573 _dio0_ctl.rise(callback(this, &SX1272_LoRaRadio::dio0_irq_isr));
brunnobbco 0:561d07a737bc 1574
brunnobbco 0:561d07a737bc 1575 if (_dio1_pin != NC) {
brunnobbco 0:561d07a737bc 1576 _dio1_ctl.rise(callback(this, &SX1272_LoRaRadio::dio1_irq_isr));
brunnobbco 0:561d07a737bc 1577 }
brunnobbco 0:561d07a737bc 1578
brunnobbco 1:3bdd6f917bf5 1579 if (_dio2_pin != NC) {
brunnobbco 1:3bdd6f917bf5 1580 _dio2_ctl.rise(callback(this, &SX1272_LoRaRadio::dio2_irq_isr));
brunnobbco 0:561d07a737bc 1581 }
brunnobbco 0:561d07a737bc 1582 }
brunnobbco 0:561d07a737bc 1583
brunnobbco 0:561d07a737bc 1584 /**
brunnobbco 0:561d07a737bc 1585 * Sets the module in low power mode by disconnecting
brunnobbco 0:561d07a737bc 1586 * TX and RX submodules, turning off power amplifier etc.
brunnobbco 0:561d07a737bc 1587 */
brunnobbco 0:561d07a737bc 1588 void SX1272_LoRaRadio::set_low_power_mode(bool status)
brunnobbco 0:561d07a737bc 1589 {
brunnobbco 0:561d07a737bc 1590 if (radio_is_active != status) {
brunnobbco 0:561d07a737bc 1591 radio_is_active = status;
brunnobbco 0:561d07a737bc 1592
brunnobbco 0:561d07a737bc 1593 if (status == false) {
brunnobbco 0:561d07a737bc 1594 if (_rf_ctrls.rf_switch_ctl1 != NC) {
brunnobbco 0:561d07a737bc 1595 _rf_switch_ctl1 = 0;
brunnobbco 0:561d07a737bc 1596 }
brunnobbco 0:561d07a737bc 1597 if (_rf_ctrls.rf_switch_ctl2 != NC) {
brunnobbco 0:561d07a737bc 1598 _rf_switch_ctl2 = 0;
brunnobbco 0:561d07a737bc 1599 }
brunnobbco 0:561d07a737bc 1600
brunnobbco 0:561d07a737bc 1601 if (_rf_ctrls.pwr_amp_ctl != NC) {
brunnobbco 0:561d07a737bc 1602 _pwr_amp_ctl = 0;
brunnobbco 0:561d07a737bc 1603 }
brunnobbco 0:561d07a737bc 1604
brunnobbco 0:561d07a737bc 1605 if (_rf_ctrls.txctl != NC) {
brunnobbco 0:561d07a737bc 1606 _txctl = 0;
brunnobbco 0:561d07a737bc 1607 }
brunnobbco 0:561d07a737bc 1608
brunnobbco 0:561d07a737bc 1609 if (_rf_ctrls.rxctl != NC) {
brunnobbco 0:561d07a737bc 1610 _rxctl = 0;
brunnobbco 0:561d07a737bc 1611 }
brunnobbco 0:561d07a737bc 1612
brunnobbco 0:561d07a737bc 1613 if (_rf_ctrls.ant_switch != NC) {
brunnobbco 0:561d07a737bc 1614 _ant_switch = 0;
brunnobbco 0:561d07a737bc 1615 }
brunnobbco 0:561d07a737bc 1616 } else {
brunnobbco 0:561d07a737bc 1617 default_antenna_switch_ctrls();
brunnobbco 0:561d07a737bc 1618 }
brunnobbco 0:561d07a737bc 1619 }
brunnobbco 0:561d07a737bc 1620 }
brunnobbco 0:561d07a737bc 1621
brunnobbco 0:561d07a737bc 1622 /*****************************************************************************
brunnobbco 0:561d07a737bc 1623 * Interrupt service routines (ISRs) - set signals to the irq_thread *
brunnobbco 0:561d07a737bc 1624 ****************************************************************************/
brunnobbco 0:561d07a737bc 1625 void SX1272_LoRaRadio::dio0_irq_isr()
brunnobbco 0:561d07a737bc 1626 {
brunnobbco 0:561d07a737bc 1627 #ifdef MBED_CONF_RTOS_PRESENT
brunnobbco 0:561d07a737bc 1628 irq_thread.flags_set(SIG_DIO0);
brunnobbco 0:561d07a737bc 1629 #else
brunnobbco 0:561d07a737bc 1630 handle_dio0_irq();
brunnobbco 0:561d07a737bc 1631 #endif
brunnobbco 0:561d07a737bc 1632 }
brunnobbco 0:561d07a737bc 1633
brunnobbco 0:561d07a737bc 1634 void SX1272_LoRaRadio::dio1_irq_isr()
brunnobbco 0:561d07a737bc 1635 {
brunnobbco 0:561d07a737bc 1636 #ifdef MBED_CONF_RTOS_PRESENT
brunnobbco 0:561d07a737bc 1637 irq_thread.flags_set(SIG_DIO1);
brunnobbco 0:561d07a737bc 1638 #else
brunnobbco 0:561d07a737bc 1639 handle_dio1_irq();
brunnobbco 0:561d07a737bc 1640 #endif
brunnobbco 0:561d07a737bc 1641 }
brunnobbco 0:561d07a737bc 1642
brunnobbco 0:561d07a737bc 1643 void SX1272_LoRaRadio::dio2_irq_isr()
brunnobbco 0:561d07a737bc 1644 {
brunnobbco 0:561d07a737bc 1645 #ifdef MBED_CONF_RTOS_PRESENT
brunnobbco 0:561d07a737bc 1646 irq_thread.flags_set(SIG_DIO2);
brunnobbco 0:561d07a737bc 1647 #else
brunnobbco 0:561d07a737bc 1648 handle_dio2_irq();
brunnobbco 0:561d07a737bc 1649 #endif
brunnobbco 0:561d07a737bc 1650 }
brunnobbco 0:561d07a737bc 1651
brunnobbco 0:561d07a737bc 1652 // This is not a hardware interrupt
brunnobbco 0:561d07a737bc 1653 // we invoke it ourselves based upon
brunnobbco 0:561d07a737bc 1654 // our timers
brunnobbco 0:561d07a737bc 1655 void SX1272_LoRaRadio::timeout_irq_isr()
brunnobbco 0:561d07a737bc 1656 {
brunnobbco 0:561d07a737bc 1657 #ifdef MBED_CONF_RTOS_PRESENT
brunnobbco 0:561d07a737bc 1658 irq_thread.flags_set(SIG_TIMOUT);
brunnobbco 0:561d07a737bc 1659 #else
brunnobbco 0:561d07a737bc 1660 handle_timeout_irq();
brunnobbco 0:561d07a737bc 1661 #endif
brunnobbco 0:561d07a737bc 1662 }
brunnobbco 0:561d07a737bc 1663
brunnobbco 0:561d07a737bc 1664 void SX1272_LoRaRadio::rxsync_irq_isr()
brunnobbco 0:561d07a737bc 1665 {
brunnobbco 0:561d07a737bc 1666 #ifdef MBED_CONF_RTOS_PRESENT
brunnobbco 0:561d07a737bc 1667 irq_thread.flags_set(SIG_RXSYNC);
brunnobbco 0:561d07a737bc 1668 #else
brunnobbco 0:561d07a737bc 1669 handle_rxsync_irq();
brunnobbco 0:561d07a737bc 1670 #endif
brunnobbco 0:561d07a737bc 1671 }
brunnobbco 0:561d07a737bc 1672
brunnobbco 1:3bdd6f917bf5 1673 void SX1272_LoRaRadio::lrcad_irq_isr()
brunnobbco 1:3bdd6f917bf5 1674 {
brunnobbco 1:3bdd6f917bf5 1675 #ifdef MBED_CONF_RTOS_PRESENT
brunnobbco 1:3bdd6f917bf5 1676 irq_thread.flags_set(SIG_LRCAD);
brunnobbco 1:3bdd6f917bf5 1677 #else
brunnobbco 1:3bdd6f917bf5 1678 handle_lrcad_irq();
brunnobbco 1:3bdd6f917bf5 1679 #endif
brunnobbco 1:3bdd6f917bf5 1680 }
brunnobbco 1:3bdd6f917bf5 1681
brunnobbco 1:3bdd6f917bf5 1682 void SX1272_LoRaRadio::lrhop_irq_isr()
brunnobbco 1:3bdd6f917bf5 1683 {
brunnobbco 1:3bdd6f917bf5 1684 #ifdef MBED_CONF_RTOS_PRESENT
brunnobbco 1:3bdd6f917bf5 1685 irq_thread.flags_set(SIG_LRHOP);
brunnobbco 1:3bdd6f917bf5 1686 #else
brunnobbco 1:3bdd6f917bf5 1687 handle_lrhop_irq();
brunnobbco 1:3bdd6f917bf5 1688 #endif
brunnobbco 1:3bdd6f917bf5 1689 }
brunnobbco 1:3bdd6f917bf5 1690
brunnobbco 0:561d07a737bc 1691 /******************************************************************************
brunnobbco 0:561d07a737bc 1692 * Interrupt Handlers *
brunnobbco 0:561d07a737bc 1693 *****************************************************************************/
brunnobbco 0:561d07a737bc 1694
brunnobbco 0:561d07a737bc 1695 void SX1272_LoRaRadio::handle_dio0_irq()
brunnobbco 0:561d07a737bc 1696 {
brunnobbco 0:561d07a737bc 1697 volatile uint8_t irqFlags = 0;
brunnobbco 0:561d07a737bc 1698
brunnobbco 0:561d07a737bc 1699 switch (_rf_settings.state) {
brunnobbco 0:561d07a737bc 1700 case RF_RX_RUNNING:
brunnobbco 0:561d07a737bc 1701 switch (_rf_settings.modem) {
brunnobbco 0:561d07a737bc 1702 case MODEM_FSK:
brunnobbco 0:561d07a737bc 1703 if (_rf_settings.fsk.crc_on == true) {
brunnobbco 0:561d07a737bc 1704 irqFlags = read_register(REG_IRQFLAGS2);
brunnobbco 0:561d07a737bc 1705 if ((irqFlags & RF_IRQFLAGS2_CRCOK)
brunnobbco 0:561d07a737bc 1706 != RF_IRQFLAGS2_CRCOK) {
brunnobbco 0:561d07a737bc 1707 // Clear Irqs
brunnobbco 0:561d07a737bc 1708 write_to_register(REG_IRQFLAGS1, RF_IRQFLAGS1_RSSI |
brunnobbco 0:561d07a737bc 1709 RF_IRQFLAGS1_PREAMBLEDETECT |
brunnobbco 0:561d07a737bc 1710 RF_IRQFLAGS1_SYNCADDRESSMATCH);
brunnobbco 0:561d07a737bc 1711 write_to_register(REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN);
brunnobbco 0:561d07a737bc 1712
brunnobbco 0:561d07a737bc 1713
brunnobbco 0:561d07a737bc 1714 if (_rf_settings.fsk.rx_continuous == false) {
brunnobbco 0:561d07a737bc 1715 _rf_settings.state = RF_IDLE;
brunnobbco 0:561d07a737bc 1716 } else {
brunnobbco 0:561d07a737bc 1717 // Continuous mode restart Rx chain
brunnobbco 0:561d07a737bc 1718 write_to_register(REG_RXCONFIG,
brunnobbco 0:561d07a737bc 1719 read_register(REG_RXCONFIG) |
brunnobbco 0:561d07a737bc 1720 RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK);
brunnobbco 0:561d07a737bc 1721 }
brunnobbco 0:561d07a737bc 1722
brunnobbco 0:561d07a737bc 1723 if ((_radio_events != NULL)
brunnobbco 0:561d07a737bc 1724 && (_radio_events->rx_error)) {
brunnobbco 0:561d07a737bc 1725 _radio_events->rx_error();
brunnobbco 0:561d07a737bc 1726 }
brunnobbco 0:561d07a737bc 1727 _rf_settings.fsk_packet_handler.preamble_detected = 0;
brunnobbco 0:561d07a737bc 1728 _rf_settings.fsk_packet_handler.sync_word_detected = 0;
brunnobbco 0:561d07a737bc 1729 _rf_settings.fsk_packet_handler.nb_bytes = 0;
brunnobbco 0:561d07a737bc 1730 _rf_settings.fsk_packet_handler.size = 0;
brunnobbco 0:561d07a737bc 1731 // break from here, a CRC error happened, RX_ERROR
brunnobbco 0:561d07a737bc 1732 // was notified. No need to go any further
brunnobbco 0:561d07a737bc 1733 break;
brunnobbco 0:561d07a737bc 1734 }
brunnobbco 0:561d07a737bc 1735 }
brunnobbco 0:561d07a737bc 1736
brunnobbco 0:561d07a737bc 1737 // This block was moved from dio2_handler.
brunnobbco 0:561d07a737bc 1738 // We can have a snapshot of RSSI here as at this point it
brunnobbco 0:561d07a737bc 1739 // should be more smoothed out.
brunnobbco 0:561d07a737bc 1740 _rf_settings.fsk_packet_handler.rssi_value = -(read_register(REG_RSSIVALUE) >> 1);
brunnobbco 0:561d07a737bc 1741 _rf_settings.fsk_packet_handler.afc_value = (int32_t)(float)(((uint16_t)read_register(REG_AFCMSB) << 8) |
brunnobbco 0:561d07a737bc 1742 (uint16_t)read_register(REG_AFCLSB)) *
brunnobbco 0:561d07a737bc 1743 (float)FREQ_STEP;
brunnobbco 0:561d07a737bc 1744 _rf_settings.fsk_packet_handler.rx_gain = (read_register(REG_LNA) >> 5) & 0x07;
brunnobbco 0:561d07a737bc 1745
brunnobbco 0:561d07a737bc 1746 // Read received packet size
brunnobbco 0:561d07a737bc 1747 if ((_rf_settings.fsk_packet_handler.size == 0)
brunnobbco 0:561d07a737bc 1748 && (_rf_settings.fsk_packet_handler.nb_bytes == 0)) {
brunnobbco 0:561d07a737bc 1749 if (_rf_settings.fsk.fix_len == false) {
brunnobbco 0:561d07a737bc 1750 read_fifo((uint8_t*) &_rf_settings.fsk_packet_handler.size, 1);
brunnobbco 0:561d07a737bc 1751 } else {
brunnobbco 0:561d07a737bc 1752 _rf_settings.fsk_packet_handler.size = read_register(REG_PAYLOADLENGTH);
brunnobbco 0:561d07a737bc 1753 }
brunnobbco 0:561d07a737bc 1754 read_fifo(_data_buffer + _rf_settings.fsk_packet_handler.nb_bytes,
brunnobbco 0:561d07a737bc 1755 _rf_settings.fsk_packet_handler.size - _rf_settings.fsk_packet_handler.nb_bytes);
brunnobbco 0:561d07a737bc 1756 _rf_settings.fsk_packet_handler.nb_bytes +=
brunnobbco 0:561d07a737bc 1757 (_rf_settings.fsk_packet_handler.size - _rf_settings.fsk_packet_handler.nb_bytes);
brunnobbco 0:561d07a737bc 1758 } else {
brunnobbco 0:561d07a737bc 1759 read_fifo(_data_buffer + _rf_settings.fsk_packet_handler.nb_bytes,
brunnobbco 0:561d07a737bc 1760 _rf_settings.fsk_packet_handler.size - _rf_settings.fsk_packet_handler.nb_bytes);
brunnobbco 0:561d07a737bc 1761 _rf_settings.fsk_packet_handler.nb_bytes +=
brunnobbco 0:561d07a737bc 1762 (_rf_settings.fsk_packet_handler.size - _rf_settings.fsk_packet_handler.nb_bytes);
brunnobbco 0:561d07a737bc 1763 }
brunnobbco 0:561d07a737bc 1764
brunnobbco 0:561d07a737bc 1765 if (_rf_settings.fsk.rx_continuous == false) {
brunnobbco 0:561d07a737bc 1766 _rf_settings.state = RF_IDLE;
brunnobbco 0:561d07a737bc 1767 } else {
brunnobbco 0:561d07a737bc 1768 // Continuous mode restart Rx chain
brunnobbco 0:561d07a737bc 1769 write_to_register(REG_RXCONFIG, read_register(REG_RXCONFIG)
brunnobbco 0:561d07a737bc 1770 | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK);
brunnobbco 0:561d07a737bc 1771 }
brunnobbco 0:561d07a737bc 1772
brunnobbco 0:561d07a737bc 1773 if ((_radio_events != NULL) && (_radio_events->rx_done)) {
brunnobbco 0:561d07a737bc 1774 _radio_events->rx_done(
brunnobbco 0:561d07a737bc 1775 _data_buffer,
brunnobbco 0:561d07a737bc 1776 _rf_settings.fsk_packet_handler.size,
brunnobbco 0:561d07a737bc 1777 _rf_settings.fsk_packet_handler.rssi_value, 0);
brunnobbco 0:561d07a737bc 1778 }
brunnobbco 0:561d07a737bc 1779 _rf_settings.fsk_packet_handler.preamble_detected = 0;
brunnobbco 0:561d07a737bc 1780 _rf_settings.fsk_packet_handler.sync_word_detected = 0;
brunnobbco 0:561d07a737bc 1781 _rf_settings.fsk_packet_handler.nb_bytes = 0;
brunnobbco 0:561d07a737bc 1782 _rf_settings.fsk_packet_handler.size = 0;
brunnobbco 0:561d07a737bc 1783 break;
brunnobbco 0:561d07a737bc 1784 case MODEM_LORA: {
brunnobbco 0:561d07a737bc 1785 int8_t snr = 0;
brunnobbco 0:561d07a737bc 1786
brunnobbco 0:561d07a737bc 1787 // Clear Irq
brunnobbco 0:561d07a737bc 1788 write_to_register(REG_LR_IRQFLAGS, RFLR_IRQFLAGS_RXDONE);
brunnobbco 0:561d07a737bc 1789
brunnobbco 0:561d07a737bc 1790 irqFlags = read_register(REG_LR_IRQFLAGS);
brunnobbco 0:561d07a737bc 1791 if ((irqFlags & RFLR_IRQFLAGS_PAYLOADCRCERROR_MASK)
brunnobbco 0:561d07a737bc 1792 == RFLR_IRQFLAGS_PAYLOADCRCERROR) {
brunnobbco 0:561d07a737bc 1793 // Clear Irq
brunnobbco 0:561d07a737bc 1794 write_to_register(REG_LR_IRQFLAGS,
brunnobbco 0:561d07a737bc 1795 RFLR_IRQFLAGS_PAYLOADCRCERROR);
brunnobbco 0:561d07a737bc 1796
brunnobbco 0:561d07a737bc 1797 if (_rf_settings.lora.rx_continuous == false) {
brunnobbco 0:561d07a737bc 1798 _rf_settings.state = RF_IDLE;
brunnobbco 0:561d07a737bc 1799 }
brunnobbco 0:561d07a737bc 1800
brunnobbco 0:561d07a737bc 1801 if ((_radio_events != NULL)
brunnobbco 0:561d07a737bc 1802 && (_radio_events->rx_error)) {
brunnobbco 0:561d07a737bc 1803 _radio_events->rx_error();
brunnobbco 0:561d07a737bc 1804 }
brunnobbco 0:561d07a737bc 1805 break;
brunnobbco 0:561d07a737bc 1806 }
brunnobbco 0:561d07a737bc 1807
brunnobbco 0:561d07a737bc 1808 _rf_settings.lora_packet_handler.snr_value = read_register(REG_LR_PKTSNRVALUE);
brunnobbco 0:561d07a737bc 1809 if (_rf_settings.lora_packet_handler.snr_value & 0x80) // The SNR sign bit is 1
brunnobbco 0:561d07a737bc 1810 {
brunnobbco 0:561d07a737bc 1811 // Invert and divide by 4
brunnobbco 0:561d07a737bc 1812 snr = ((~_rf_settings.lora_packet_handler.snr_value + 1) & 0xFF) >> 2;
brunnobbco 0:561d07a737bc 1813 snr = -snr;
brunnobbco 0:561d07a737bc 1814 } else {
brunnobbco 0:561d07a737bc 1815 // Divide by 4
brunnobbco 0:561d07a737bc 1816 snr =(_rf_settings.lora_packet_handler.snr_value & 0xFF) >> 2;
brunnobbco 0:561d07a737bc 1817 }
brunnobbco 0:561d07a737bc 1818
brunnobbco 0:561d07a737bc 1819 int16_t rssi = read_register(REG_LR_PKTRSSIVALUE);
brunnobbco 0:561d07a737bc 1820 if (snr < 0) {
brunnobbco 0:561d07a737bc 1821 _rf_settings.lora_packet_handler.rssi_value =
brunnobbco 0:561d07a737bc 1822 RSSI_OFFSET + rssi + (rssi >> 4) + snr;
brunnobbco 0:561d07a737bc 1823 } else {
brunnobbco 0:561d07a737bc 1824 _rf_settings.lora_packet_handler.rssi_value =
brunnobbco 0:561d07a737bc 1825 RSSI_OFFSET + rssi + (rssi >> 4);
brunnobbco 0:561d07a737bc 1826 }
brunnobbco 0:561d07a737bc 1827
brunnobbco 0:561d07a737bc 1828 _rf_settings.lora_packet_handler.size = read_register(REG_LR_RXNBBYTES);
brunnobbco 0:561d07a737bc 1829 read_fifo(_data_buffer, _rf_settings.lora_packet_handler.size);
brunnobbco 0:561d07a737bc 1830
brunnobbco 0:561d07a737bc 1831 if (_rf_settings.lora.rx_continuous == false) {
brunnobbco 0:561d07a737bc 1832 _rf_settings.state = RF_IDLE;
brunnobbco 0:561d07a737bc 1833 }
brunnobbco 0:561d07a737bc 1834
brunnobbco 0:561d07a737bc 1835 if ((_radio_events != NULL)
brunnobbco 0:561d07a737bc 1836 && (_radio_events->rx_done)) {
brunnobbco 0:561d07a737bc 1837 _radio_events->rx_done(
brunnobbco 0:561d07a737bc 1838 _data_buffer,
brunnobbco 0:561d07a737bc 1839 _rf_settings.lora_packet_handler.size,
brunnobbco 0:561d07a737bc 1840 _rf_settings.lora_packet_handler.rssi_value,
brunnobbco 0:561d07a737bc 1841 _rf_settings.lora_packet_handler.snr_value);
brunnobbco 0:561d07a737bc 1842 }
brunnobbco 0:561d07a737bc 1843 }
brunnobbco 0:561d07a737bc 1844 break;
brunnobbco 0:561d07a737bc 1845 default:
brunnobbco 0:561d07a737bc 1846 break;
brunnobbco 0:561d07a737bc 1847 }
brunnobbco 0:561d07a737bc 1848 break;
brunnobbco 0:561d07a737bc 1849 case RF_TX_RUNNING:
brunnobbco 0:561d07a737bc 1850 tx_timeout_timer.detach();
brunnobbco 0:561d07a737bc 1851 // TxDone interrupt
brunnobbco 0:561d07a737bc 1852 switch (_rf_settings.modem) {
brunnobbco 0:561d07a737bc 1853 case MODEM_LORA:
brunnobbco 0:561d07a737bc 1854 // Clear Irq
brunnobbco 0:561d07a737bc 1855 write_to_register( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_TXDONE);
brunnobbco 0:561d07a737bc 1856 // Intentional fall through
brunnobbco 0:561d07a737bc 1857 case MODEM_FSK:
brunnobbco 0:561d07a737bc 1858 default:
brunnobbco 0:561d07a737bc 1859 _rf_settings.state = RF_IDLE;
brunnobbco 0:561d07a737bc 1860 if ((_radio_events != NULL)
brunnobbco 0:561d07a737bc 1861 && (_radio_events->tx_done)) {
brunnobbco 0:561d07a737bc 1862 _radio_events->tx_done();
brunnobbco 0:561d07a737bc 1863 }
brunnobbco 0:561d07a737bc 1864 break;
brunnobbco 0:561d07a737bc 1865 }
brunnobbco 0:561d07a737bc 1866 break;
brunnobbco 0:561d07a737bc 1867 default:
brunnobbco 0:561d07a737bc 1868 break;
brunnobbco 0:561d07a737bc 1869 }
brunnobbco 0:561d07a737bc 1870 }
brunnobbco 0:561d07a737bc 1871
brunnobbco 0:561d07a737bc 1872 void SX1272_LoRaRadio::handle_dio1_irq()
brunnobbco 0:561d07a737bc 1873 {
brunnobbco 0:561d07a737bc 1874 switch(_rf_settings.state )
brunnobbco 0:561d07a737bc 1875 {
brunnobbco 0:561d07a737bc 1876 case RF_RX_RUNNING:
brunnobbco 0:561d07a737bc 1877 switch(_rf_settings.modem ) {
brunnobbco 0:561d07a737bc 1878 case MODEM_FSK:
brunnobbco 0:561d07a737bc 1879 // FifoLevel interrupt
brunnobbco 0:561d07a737bc 1880 // Read received packet size
brunnobbco 0:561d07a737bc 1881 if( ( _rf_settings.fsk_packet_handler.size == 0 ) && ( _rf_settings.fsk_packet_handler.nb_bytes == 0 ) )
brunnobbco 0:561d07a737bc 1882 {
brunnobbco 0:561d07a737bc 1883 if( _rf_settings.fsk.fix_len == false )
brunnobbco 0:561d07a737bc 1884 {
brunnobbco 0:561d07a737bc 1885 read_fifo( ( uint8_t* )&_rf_settings.fsk_packet_handler.size, 1 );
brunnobbco 0:561d07a737bc 1886 }
brunnobbco 0:561d07a737bc 1887 else
brunnobbco 0:561d07a737bc 1888 {
brunnobbco 0:561d07a737bc 1889 _rf_settings.fsk_packet_handler.size = read_register(REG_PAYLOADLENGTH);
brunnobbco 0:561d07a737bc 1890 }
brunnobbco 0:561d07a737bc 1891 }
brunnobbco 0:561d07a737bc 1892
brunnobbco 0:561d07a737bc 1893 if( ( _rf_settings.fsk_packet_handler.size - _rf_settings.fsk_packet_handler.nb_bytes ) > _rf_settings.fsk_packet_handler.fifo_thresh )
brunnobbco 0:561d07a737bc 1894 {
brunnobbco 0:561d07a737bc 1895 read_fifo( ( _data_buffer + _rf_settings.fsk_packet_handler.nb_bytes ), _rf_settings.fsk_packet_handler.fifo_thresh );
brunnobbco 0:561d07a737bc 1896 _rf_settings.fsk_packet_handler.nb_bytes += _rf_settings.fsk_packet_handler.fifo_thresh;
brunnobbco 0:561d07a737bc 1897 }
brunnobbco 0:561d07a737bc 1898 else
brunnobbco 0:561d07a737bc 1899 {
brunnobbco 0:561d07a737bc 1900 read_fifo( ( _data_buffer + _rf_settings.fsk_packet_handler.nb_bytes ), _rf_settings.fsk_packet_handler.size - _rf_settings.fsk_packet_handler.nb_bytes );
brunnobbco 0:561d07a737bc 1901 _rf_settings.fsk_packet_handler.nb_bytes += ( _rf_settings.fsk_packet_handler.size - _rf_settings.fsk_packet_handler.nb_bytes );
brunnobbco 0:561d07a737bc 1902 }
brunnobbco 0:561d07a737bc 1903 break;
brunnobbco 0:561d07a737bc 1904 case MODEM_LORA:
brunnobbco 0:561d07a737bc 1905 break;
brunnobbco 0:561d07a737bc 1906 default:
brunnobbco 0:561d07a737bc 1907 break;
brunnobbco 0:561d07a737bc 1908 }
brunnobbco 0:561d07a737bc 1909 break;
brunnobbco 0:561d07a737bc 1910 case RF_TX_RUNNING:
brunnobbco 0:561d07a737bc 1911 switch( _rf_settings.modem )
brunnobbco 0:561d07a737bc 1912 {
brunnobbco 0:561d07a737bc 1913 case MODEM_FSK:
brunnobbco 0:561d07a737bc 1914 // FifoLevel interrupt
brunnobbco 0:561d07a737bc 1915 if( ( _rf_settings.fsk_packet_handler.size - _rf_settings.fsk_packet_handler.nb_bytes ) > _rf_settings.fsk_packet_handler.chunk_size )
brunnobbco 0:561d07a737bc 1916 {
brunnobbco 0:561d07a737bc 1917 write_fifo(( _data_buffer + _rf_settings.fsk_packet_handler.nb_bytes ), _rf_settings.fsk_packet_handler.chunk_size );
brunnobbco 0:561d07a737bc 1918 _rf_settings.fsk_packet_handler.nb_bytes += _rf_settings.fsk_packet_handler.chunk_size;
brunnobbco 0:561d07a737bc 1919 }
brunnobbco 0:561d07a737bc 1920 else
brunnobbco 0:561d07a737bc 1921 {
brunnobbco 0:561d07a737bc 1922 // Write the last chunk of data
brunnobbco 0:561d07a737bc 1923 write_fifo( _data_buffer + _rf_settings.fsk_packet_handler.nb_bytes, _rf_settings.fsk_packet_handler.size - _rf_settings.fsk_packet_handler.nb_bytes );
brunnobbco 0:561d07a737bc 1924 _rf_settings.fsk_packet_handler.nb_bytes += _rf_settings.fsk_packet_handler.size - _rf_settings.fsk_packet_handler.nb_bytes;
brunnobbco 0:561d07a737bc 1925 }
brunnobbco 0:561d07a737bc 1926 break;
brunnobbco 0:561d07a737bc 1927 case MODEM_LORA:
brunnobbco 0:561d07a737bc 1928 break;
brunnobbco 0:561d07a737bc 1929 default:
brunnobbco 0:561d07a737bc 1930 break;
brunnobbco 0:561d07a737bc 1931 }
brunnobbco 0:561d07a737bc 1932 break;
brunnobbco 0:561d07a737bc 1933 default:
brunnobbco 0:561d07a737bc 1934 break;
brunnobbco 0:561d07a737bc 1935 }
brunnobbco 0:561d07a737bc 1936 }
brunnobbco 0:561d07a737bc 1937
brunnobbco 0:561d07a737bc 1938 void SX1272_LoRaRadio::handle_dio2_irq(void)
brunnobbco 0:561d07a737bc 1939 {
brunnobbco 0:561d07a737bc 1940 switch(_rf_settings.state )
brunnobbco 0:561d07a737bc 1941 {
brunnobbco 0:561d07a737bc 1942 case RF_RX_RUNNING:
brunnobbco 0:561d07a737bc 1943 switch( _rf_settings.modem )
brunnobbco 0:561d07a737bc 1944 {
brunnobbco 0:561d07a737bc 1945 case MODEM_FSK:
brunnobbco 0:561d07a737bc 1946 _rf_settings.fsk_packet_handler.preamble_detected = 0;
brunnobbco 0:561d07a737bc 1947 _rf_settings.fsk_packet_handler.sync_word_detected = 0;
brunnobbco 0:561d07a737bc 1948 _rf_settings.fsk_packet_handler.nb_bytes = 0;
brunnobbco 0:561d07a737bc 1949 _rf_settings.fsk_packet_handler.size = 0;
brunnobbco 0:561d07a737bc 1950
brunnobbco 0:561d07a737bc 1951 // Clear Irqs
brunnobbco 0:561d07a737bc 1952 write_to_register(REG_IRQFLAGS1, RF_IRQFLAGS1_RSSI |
brunnobbco 0:561d07a737bc 1953 RF_IRQFLAGS1_PREAMBLEDETECT |
brunnobbco 0:561d07a737bc 1954 RF_IRQFLAGS1_SYNCADDRESSMATCH |
brunnobbco 0:561d07a737bc 1955 RF_IRQFLAGS1_TIMEOUT);
brunnobbco 0:561d07a737bc 1956
brunnobbco 0:561d07a737bc 1957 write_to_register( REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN);
brunnobbco 0:561d07a737bc 1958
brunnobbco 0:561d07a737bc 1959 if (_rf_settings.fsk.rx_continuous == true) {
brunnobbco 0:561d07a737bc 1960 // Continuous mode restart Rx chain
brunnobbco 0:561d07a737bc 1961 write_to_register( REG_RXCONFIG,
brunnobbco 0:561d07a737bc 1962 read_register(REG_RXCONFIG) |
brunnobbco 0:561d07a737bc 1963 RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK);
brunnobbco 0:561d07a737bc 1964 } else {
brunnobbco 0:561d07a737bc 1965 _rf_settings.state = RF_IDLE;
brunnobbco 0:561d07a737bc 1966 }
brunnobbco 0:561d07a737bc 1967
brunnobbco 0:561d07a737bc 1968 if ((_radio_events != NULL)
brunnobbco 0:561d07a737bc 1969 && (_radio_events->rx_timeout)) {
brunnobbco 0:561d07a737bc 1970 _radio_events->rx_timeout();
brunnobbco 0:561d07a737bc 1971 }
brunnobbco 0:561d07a737bc 1972
brunnobbco 0:561d07a737bc 1973 break;
brunnobbco 0:561d07a737bc 1974 case MODEM_LORA:
brunnobbco 0:561d07a737bc 1975 break;
brunnobbco 0:561d07a737bc 1976 default:
brunnobbco 0:561d07a737bc 1977 break;
brunnobbco 0:561d07a737bc 1978 }
brunnobbco 0:561d07a737bc 1979 break;
brunnobbco 0:561d07a737bc 1980 case RF_TX_RUNNING:
brunnobbco 0:561d07a737bc 1981 switch( _rf_settings.modem )
brunnobbco 0:561d07a737bc 1982 {
brunnobbco 0:561d07a737bc 1983 case MODEM_FSK:
brunnobbco 0:561d07a737bc 1984 break;
brunnobbco 0:561d07a737bc 1985 case MODEM_LORA:
brunnobbco 0:561d07a737bc 1986 break;
brunnobbco 0:561d07a737bc 1987 default:
brunnobbco 0:561d07a737bc 1988 break;
brunnobbco 0:561d07a737bc 1989 }
brunnobbco 0:561d07a737bc 1990 break;
brunnobbco 0:561d07a737bc 1991 default:
brunnobbco 0:561d07a737bc 1992 break;
brunnobbco 0:561d07a737bc 1993 }
brunnobbco 0:561d07a737bc 1994 }
brunnobbco 0:561d07a737bc 1995
brunnobbco 0:561d07a737bc 1996 void SX1272_LoRaRadio::handle_timeout_irq()
brunnobbco 0:561d07a737bc 1997 {
brunnobbco 0:561d07a737bc 1998 tx_timeout_timer.detach();
brunnobbco 0:561d07a737bc 1999
brunnobbco 0:561d07a737bc 2000 if (_rf_settings.state == RF_TX_RUNNING) {
brunnobbco 0:561d07a737bc 2001 // Tx timeout shouldn't happen.
brunnobbco 0:561d07a737bc 2002 // But it has been observed that when it happens it is a result of a
brunnobbco 0:561d07a737bc 2003 // corrupted SPI transfer
brunnobbco 0:561d07a737bc 2004 // The workaround is to put the radio in a known state.
brunnobbco 0:561d07a737bc 2005 // Thus, we re-initialize it.
brunnobbco 0:561d07a737bc 2006
brunnobbco 0:561d07a737bc 2007 // Initialize radio default values
brunnobbco 0:561d07a737bc 2008 set_operation_mode(RF_OPMODE_SLEEP);
brunnobbco 0:561d07a737bc 2009
brunnobbco 0:561d07a737bc 2010 setup_registers();
brunnobbco 0:561d07a737bc 2011
brunnobbco 0:561d07a737bc 2012 set_modem(MODEM_FSK);
brunnobbco 0:561d07a737bc 2013
brunnobbco 0:561d07a737bc 2014 // Restore previous network type setting.
brunnobbco 0:561d07a737bc 2015 set_public_network(_rf_settings.lora.public_network);
brunnobbco 0:561d07a737bc 2016
brunnobbco 0:561d07a737bc 2017 _rf_settings.state = RF_IDLE;
brunnobbco 0:561d07a737bc 2018
brunnobbco 0:561d07a737bc 2019 if ((_radio_events != NULL) && (_radio_events->tx_timeout)) {
brunnobbco 0:561d07a737bc 2020 _radio_events->tx_timeout();
brunnobbco 0:561d07a737bc 2021 }
brunnobbco 0:561d07a737bc 2022 }
brunnobbco 0:561d07a737bc 2023 }
brunnobbco 0:561d07a737bc 2024
brunnobbco 0:561d07a737bc 2025 void SX1272_LoRaRadio::handle_rxsync_irq()
brunnobbco 0:561d07a737bc 2026 {
brunnobbco 0:561d07a737bc 2027 rx_sync_timer.detach();
brunnobbco 0:561d07a737bc 2028
brunnobbco 1:3bdd6f917bf5 2029 if (_rf_settings.modem != MODEM_LORA) {
brunnobbco 1:3bdd6f917bf5 2030 return;
brunnobbco 1:3bdd6f917bf5 2031 }
brunnobbco 1:3bdd6f917bf5 2032 if (_rf_settings.state != RF_RX_RUNNING) {
brunnobbco 1:3bdd6f917bf5 2033 return;
brunnobbco 1:3bdd6f917bf5 2034 }
brunnobbco 1:3bdd6f917bf5 2035
brunnobbco 1:3bdd6f917bf5 2036 if((read_register(REG_OPMODE) & 0x7) == RFLR_OPMODE_RECEIVER_SINGLE)
brunnobbco 1:3bdd6f917bf5 2037 {
brunnobbco 1:3bdd6f917bf5 2038 rx_sync_timer.attach_us(callback(this, &SX1272_LoRaRadio::rxsync_irq_isr), 1000);
brunnobbco 1:3bdd6f917bf5 2039 }
brunnobbco 1:3bdd6f917bf5 2040 else
brunnobbco 0:561d07a737bc 2041 {
brunnobbco 1:3bdd6f917bf5 2042 // Sync time out
brunnobbco 1:3bdd6f917bf5 2043 _rf_settings.state = RF_IDLE;
brunnobbco 1:3bdd6f917bf5 2044
brunnobbco 1:3bdd6f917bf5 2045 if ((_radio_events != NULL) && (_radio_events->rx_timeout)) {
brunnobbco 1:3bdd6f917bf5 2046 _radio_events->rx_timeout();
brunnobbco 1:3bdd6f917bf5 2047 }
brunnobbco 1:3bdd6f917bf5 2048 }
brunnobbco 1:3bdd6f917bf5 2049 }
brunnobbco 1:3bdd6f917bf5 2050
brunnobbco 1:3bdd6f917bf5 2051 void SX1272_LoRaRadio::handle_lrcad_irq()
brunnobbco 1:3bdd6f917bf5 2052 {
brunnobbco 1:3bdd6f917bf5 2053 lora_cad_timer.detach();
brunnobbco 1:3bdd6f917bf5 2054
brunnobbco 1:3bdd6f917bf5 2055 if (_rf_settings.modem != MODEM_LORA) {
brunnobbco 1:3bdd6f917bf5 2056 return;
brunnobbco 1:3bdd6f917bf5 2057 }
brunnobbco 1:3bdd6f917bf5 2058 if (_rf_settings.state != RF_CAD) {
brunnobbco 1:3bdd6f917bf5 2059 return;
brunnobbco 1:3bdd6f917bf5 2060 }
brunnobbco 1:3bdd6f917bf5 2061
brunnobbco 1:3bdd6f917bf5 2062 if((read_register(REG_OPMODE) & 0x7) == RFLR_OPMODE_CAD)
brunnobbco 1:3bdd6f917bf5 2063 {
brunnobbco 1:3bdd6f917bf5 2064 lora_cad_timer.attach_us(callback(this, &SX1272_LoRaRadio::lrcad_irq_isr), 1000);
brunnobbco 1:3bdd6f917bf5 2065 }
brunnobbco 1:3bdd6f917bf5 2066 else
brunnobbco 1:3bdd6f917bf5 2067 {
brunnobbco 1:3bdd6f917bf5 2068 _rf_settings.state = RF_IDLE;
brunnobbco 1:3bdd6f917bf5 2069
brunnobbco 1:3bdd6f917bf5 2070 if( ( read_register( REG_LR_IRQFLAGS ) & RFLR_IRQFLAGS_CADDETECTED ) == RFLR_IRQFLAGS_CADDETECTED )
brunnobbco 0:561d07a737bc 2071 {
brunnobbco 1:3bdd6f917bf5 2072 // Clear Irq
brunnobbco 1:3bdd6f917bf5 2073 write_to_register( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDETECTED | RFLR_IRQFLAGS_CADDONE );
brunnobbco 1:3bdd6f917bf5 2074
brunnobbco 1:3bdd6f917bf5 2075 if( ( _radio_events != NULL ) && ( _radio_events->cad_done ) )
brunnobbco 1:3bdd6f917bf5 2076 {
brunnobbco 1:3bdd6f917bf5 2077 _radio_events->cad_done( true );
brunnobbco 1:3bdd6f917bf5 2078 }
brunnobbco 0:561d07a737bc 2079 }
brunnobbco 0:561d07a737bc 2080 else
brunnobbco 0:561d07a737bc 2081 {
brunnobbco 1:3bdd6f917bf5 2082 // Clear Irq
brunnobbco 1:3bdd6f917bf5 2083 write_to_register( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDONE );
brunnobbco 1:3bdd6f917bf5 2084 if( ( _radio_events != NULL ) && ( _radio_events->cad_done ) )
brunnobbco 1:3bdd6f917bf5 2085 {
brunnobbco 1:3bdd6f917bf5 2086 _radio_events->cad_done( false );
brunnobbco 0:561d07a737bc 2087 }
brunnobbco 0:561d07a737bc 2088 }
brunnobbco 0:561d07a737bc 2089 }
brunnobbco 0:561d07a737bc 2090 }
brunnobbco 0:561d07a737bc 2091
brunnobbco 1:3bdd6f917bf5 2092 void SX1272_LoRaRadio::handle_lrhop_irq()
brunnobbco 1:3bdd6f917bf5 2093 {
brunnobbco 1:3bdd6f917bf5 2094 lora_hop_timer.detach();
brunnobbco 1:3bdd6f917bf5 2095
brunnobbco 1:3bdd6f917bf5 2096 if ((_rf_settings.state != RF_TX_RUNNING) && (_rf_settings.state != RF_RX_RUNNING)) {
brunnobbco 1:3bdd6f917bf5 2097 return;
brunnobbco 1:3bdd6f917bf5 2098 }
brunnobbco 1:3bdd6f917bf5 2099 if ((_rf_settings.modem != MODEM_LORA) || (_rf_settings.lora.freq_hop_on == false)) {
brunnobbco 1:3bdd6f917bf5 2100 return;
brunnobbco 1:3bdd6f917bf5 2101 }
brunnobbco 1:3bdd6f917bf5 2102
brunnobbco 1:3bdd6f917bf5 2103 lora_hop_timer.attach_us(callback(this, &SX1272_LoRaRadio::lrhop_irq_isr), 1000);
brunnobbco 1:3bdd6f917bf5 2104
brunnobbco 1:3bdd6f917bf5 2105 if((read_register(REG_LR_IRQFLAGS) & RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL) == RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL)
brunnobbco 1:3bdd6f917bf5 2106 {
brunnobbco 1:3bdd6f917bf5 2107 write_to_register( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL );
brunnobbco 1:3bdd6f917bf5 2108
brunnobbco 1:3bdd6f917bf5 2109 if((_radio_events != NULL) && (_radio_events->fhss_change_channel))
brunnobbco 1:3bdd6f917bf5 2110 {
brunnobbco 1:3bdd6f917bf5 2111 _radio_events->fhss_change_channel((read_register( REG_LR_HOPCHANNEL ) & RFLR_HOPCHANNEL_CHANNEL_MASK));
brunnobbco 1:3bdd6f917bf5 2112 }
brunnobbco 1:3bdd6f917bf5 2113 }
brunnobbco 1:3bdd6f917bf5 2114 }