Fix ADR channel mask handling

Dependents:  

Fork of lmic_MOTE_L152RC by canuck lehead

Committer:
dudmuck
Date:
Mon Nov 16 23:52:45 2015 +0000
Revision:
9:83ae7f34e88c
Parent:
8:0faa1bb768b5
correct join behavior after link dead (joining again)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 0:f2716e543d97 1 /*******************************************************************************
dudmuck 0:f2716e543d97 2 * Copyright (c) 2014-2015 IBM Corporation.
dudmuck 0:f2716e543d97 3 * All rights reserved. This program and the accompanying materials
dudmuck 0:f2716e543d97 4 * are made available under the terms of the Eclipse Public License v1.0
dudmuck 0:f2716e543d97 5 * which accompanies this distribution, and is available at
dudmuck 0:f2716e543d97 6 * http://www.eclipse.org/legal/epl-v10.html
dudmuck 0:f2716e543d97 7 *
dudmuck 0:f2716e543d97 8 * Contributors:
dudmuck 0:f2716e543d97 9 * IBM Zurich Research Lab - initial API, implementation and documentation
dudmuck 0:f2716e543d97 10 *******************************************************************************/
dudmuck 0:f2716e543d97 11
dudmuck 0:f2716e543d97 12 #include "lmic.h"
dudmuck 3:d87012f45bf6 13 #include "mbed.h"
dudmuck 0:f2716e543d97 14
dudmuck 0:f2716e543d97 15 // ----------------------------------------
dudmuck 0:f2716e543d97 16 // Registers Mapping
dudmuck 0:f2716e543d97 17 #define RegFifo 0x00 // common
dudmuck 0:f2716e543d97 18 #define RegOpMode 0x01 // common
dudmuck 0:f2716e543d97 19 #define FSKRegBitrateMsb 0x02
dudmuck 0:f2716e543d97 20 #define FSKRegBitrateLsb 0x03
dudmuck 0:f2716e543d97 21 #define FSKRegFdevMsb 0x04
dudmuck 0:f2716e543d97 22 #define FSKRegFdevLsb 0x05
dudmuck 0:f2716e543d97 23 #define RegFrfMsb 0x06 // common
dudmuck 0:f2716e543d97 24 #define RegFrfMid 0x07 // common
dudmuck 0:f2716e543d97 25 #define RegFrfLsb 0x08 // common
dudmuck 0:f2716e543d97 26 #define RegPaConfig 0x09 // common
dudmuck 0:f2716e543d97 27 #define RegPaRamp 0x0A // common
dudmuck 0:f2716e543d97 28 #define RegOcp 0x0B // common
dudmuck 0:f2716e543d97 29 #define RegLna 0x0C // common
dudmuck 0:f2716e543d97 30 #define FSKRegRxConfig 0x0D
dudmuck 0:f2716e543d97 31 #define LORARegFifoAddrPtr 0x0D
dudmuck 0:f2716e543d97 32 #define FSKRegRssiConfig 0x0E
dudmuck 0:f2716e543d97 33 #define LORARegFifoTxBaseAddr 0x0E
dudmuck 0:f2716e543d97 34 #define FSKRegRssiCollision 0x0F
dudmuck 0:f2716e543d97 35 #define LORARegFifoRxBaseAddr 0x0F
dudmuck 0:f2716e543d97 36 #define FSKRegRssiThresh 0x10
dudmuck 0:f2716e543d97 37 #define LORARegFifoRxCurrentAddr 0x10
dudmuck 0:f2716e543d97 38 #define FSKRegRssiValue 0x11
dudmuck 0:f2716e543d97 39 #define LORARegIrqFlagsMask 0x11
dudmuck 0:f2716e543d97 40 #define FSKRegRxBw 0x12
dudmuck 0:f2716e543d97 41 #define LORARegIrqFlags 0x12
dudmuck 0:f2716e543d97 42 #define FSKRegAfcBw 0x13
dudmuck 0:f2716e543d97 43 #define LORARegRxNbBytes 0x13
dudmuck 0:f2716e543d97 44 #define FSKRegOokPeak 0x14
dudmuck 0:f2716e543d97 45 #define LORARegRxHeaderCntValueMsb 0x14
dudmuck 0:f2716e543d97 46 #define FSKRegOokFix 0x15
dudmuck 0:f2716e543d97 47 #define LORARegRxHeaderCntValueLsb 0x15
dudmuck 0:f2716e543d97 48 #define FSKRegOokAvg 0x16
dudmuck 0:f2716e543d97 49 #define LORARegRxPacketCntValueMsb 0x16
dudmuck 0:f2716e543d97 50 #define LORARegRxpacketCntValueLsb 0x17
dudmuck 0:f2716e543d97 51 #define LORARegModemStat 0x18
dudmuck 0:f2716e543d97 52 #define LORARegPktSnrValue 0x19
dudmuck 0:f2716e543d97 53 #define FSKRegAfcFei 0x1A
dudmuck 0:f2716e543d97 54 #define LORARegPktRssiValue 0x1A
dudmuck 0:f2716e543d97 55 #define FSKRegAfcMsb 0x1B
dudmuck 0:f2716e543d97 56 #define LORARegRssiValue 0x1B
dudmuck 0:f2716e543d97 57 #define FSKRegAfcLsb 0x1C
dudmuck 0:f2716e543d97 58 #define LORARegHopChannel 0x1C
dudmuck 0:f2716e543d97 59 #define FSKRegFeiMsb 0x1D
dudmuck 0:f2716e543d97 60 #define LORARegModemConfig1 0x1D
dudmuck 0:f2716e543d97 61 #define FSKRegFeiLsb 0x1E
dudmuck 0:f2716e543d97 62 #define LORARegModemConfig2 0x1E
dudmuck 0:f2716e543d97 63 #define FSKRegPreambleDetect 0x1F
dudmuck 0:f2716e543d97 64 #define LORARegSymbTimeoutLsb 0x1F
dudmuck 0:f2716e543d97 65 #define FSKRegRxTimeout1 0x20
dudmuck 0:f2716e543d97 66 #define LORARegPreambleMsb 0x20
dudmuck 0:f2716e543d97 67 #define FSKRegRxTimeout2 0x21
dudmuck 0:f2716e543d97 68 #define LORARegPreambleLsb 0x21
dudmuck 0:f2716e543d97 69 #define FSKRegRxTimeout3 0x22
dudmuck 0:f2716e543d97 70 #define LORARegPayloadLength 0x22
dudmuck 0:f2716e543d97 71 #define FSKRegRxDelay 0x23
dudmuck 0:f2716e543d97 72 #define LORARegPayloadMaxLength 0x23
dudmuck 0:f2716e543d97 73 #define FSKRegOsc 0x24
dudmuck 0:f2716e543d97 74 #define LORARegHopPeriod 0x24
dudmuck 0:f2716e543d97 75 #define FSKRegPreambleMsb 0x25
dudmuck 0:f2716e543d97 76 #define LORARegFifoRxByteAddr 0x25
dudmuck 0:f2716e543d97 77 #define LORARegModemConfig3 0x26
dudmuck 0:f2716e543d97 78 #define FSKRegPreambleLsb 0x26
dudmuck 0:f2716e543d97 79 #define FSKRegSyncConfig 0x27
dudmuck 0:f2716e543d97 80 #define LORARegFeiMsb 0x28
dudmuck 0:f2716e543d97 81 #define FSKRegSyncValue1 0x28
dudmuck 0:f2716e543d97 82 #define LORAFeiMib 0x29
dudmuck 0:f2716e543d97 83 #define FSKRegSyncValue2 0x29
dudmuck 0:f2716e543d97 84 #define LORARegFeiLsb 0x2A
dudmuck 0:f2716e543d97 85 #define FSKRegSyncValue3 0x2A
dudmuck 0:f2716e543d97 86 #define FSKRegSyncValue4 0x2B
dudmuck 0:f2716e543d97 87 #define LORARegRssiWideband 0x2C
dudmuck 0:f2716e543d97 88 #define FSKRegSyncValue5 0x2C
dudmuck 0:f2716e543d97 89 #define FSKRegSyncValue6 0x2D
dudmuck 0:f2716e543d97 90 #define FSKRegSyncValue7 0x2E
dudmuck 0:f2716e543d97 91 #define FSKRegSyncValue8 0x2F
dudmuck 0:f2716e543d97 92 #define FSKRegPacketConfig1 0x30
dudmuck 0:f2716e543d97 93 #define FSKRegPacketConfig2 0x31
dudmuck 0:f2716e543d97 94 #define LORARegDetectOptimize 0x31
dudmuck 0:f2716e543d97 95 #define FSKRegPayloadLength 0x32
dudmuck 0:f2716e543d97 96 #define FSKRegNodeAdrs 0x33
dudmuck 0:f2716e543d97 97 #define LORARegInvertIQ 0x33
dudmuck 0:f2716e543d97 98 #define FSKRegBroadcastAdrs 0x34
dudmuck 0:f2716e543d97 99 #define FSKRegFifoThresh 0x35
dudmuck 0:f2716e543d97 100 #define FSKRegSeqConfig1 0x36
dudmuck 0:f2716e543d97 101 #define FSKRegSeqConfig2 0x37
dudmuck 0:f2716e543d97 102 #define LORARegDetectionThreshold 0x37
dudmuck 0:f2716e543d97 103 #define FSKRegTimerResol 0x38
dudmuck 0:f2716e543d97 104 #define FSKRegTimer1Coef 0x39
dudmuck 0:f2716e543d97 105 #define LORARegSyncWord 0x39
dudmuck 0:f2716e543d97 106 #define FSKRegTimer2Coef 0x3A
dudmuck 0:f2716e543d97 107 #define FSKRegImageCal 0x3B
dudmuck 3:d87012f45bf6 108 #define LORARegTimingInvert 0x3B // bit2 in 0x3b set low when bit6 in 0x33 set hi (RX invert)
dudmuck 0:f2716e543d97 109 #define FSKRegTemp 0x3C
dudmuck 0:f2716e543d97 110 #define FSKRegLowBat 0x3D
dudmuck 0:f2716e543d97 111 #define FSKRegIrqFlags1 0x3E
dudmuck 0:f2716e543d97 112 #define FSKRegIrqFlags2 0x3F
dudmuck 0:f2716e543d97 113 #define RegDioMapping1 0x40 // common
dudmuck 0:f2716e543d97 114 #define RegDioMapping2 0x41 // common
dudmuck 0:f2716e543d97 115 #define RegVersion 0x42 // common
dudmuck 0:f2716e543d97 116 // #define RegAgcRef 0x43 // common
dudmuck 0:f2716e543d97 117 // #define RegAgcThresh1 0x44 // common
dudmuck 0:f2716e543d97 118 // #define RegAgcThresh2 0x45 // common
dudmuck 0:f2716e543d97 119 // #define RegAgcThresh3 0x46 // common
dudmuck 0:f2716e543d97 120 // #define RegPllHop 0x4B // common
dudmuck 0:f2716e543d97 121 // #define RegTcxo 0x58 // common
dudmuck 0:f2716e543d97 122 #define RegPaDac 0x5A // common
dudmuck 0:f2716e543d97 123 // #define RegPll 0x5C // common
dudmuck 0:f2716e543d97 124 // #define RegPllLowPn 0x5E // common
dudmuck 0:f2716e543d97 125 // #define RegFormerTemp 0x6C // common
dudmuck 0:f2716e543d97 126 // #define RegBitRateFrac 0x70 // common
dudmuck 0:f2716e543d97 127
dudmuck 0:f2716e543d97 128 // ----------------------------------------
dudmuck 0:f2716e543d97 129 // spread factors and mode for RegModemConfig2
dudmuck 0:f2716e543d97 130 #define SX1272_MC2_FSK 0x00
dudmuck 0:f2716e543d97 131 #define SX1272_MC2_SF7 0x70
dudmuck 0:f2716e543d97 132 #define SX1272_MC2_SF8 0x80
dudmuck 0:f2716e543d97 133 #define SX1272_MC2_SF9 0x90
dudmuck 0:f2716e543d97 134 #define SX1272_MC2_SF10 0xA0
dudmuck 0:f2716e543d97 135 #define SX1272_MC2_SF11 0xB0
dudmuck 0:f2716e543d97 136 #define SX1272_MC2_SF12 0xC0
dudmuck 0:f2716e543d97 137 // bandwidth for RegModemConfig1
dudmuck 0:f2716e543d97 138 #define SX1272_MC1_BW_125 0x00
dudmuck 0:f2716e543d97 139 #define SX1272_MC1_BW_250 0x40
dudmuck 0:f2716e543d97 140 #define SX1272_MC1_BW_500 0x80
dudmuck 0:f2716e543d97 141 // coding rate for RegModemConfig1
dudmuck 0:f2716e543d97 142 #define SX1272_MC1_CR_4_5 0x08
dudmuck 0:f2716e543d97 143 #define SX1272_MC1_CR_4_6 0x10
dudmuck 0:f2716e543d97 144 #define SX1272_MC1_CR_4_7 0x18
dudmuck 0:f2716e543d97 145 #define SX1272_MC1_CR_4_8 0x20
dudmuck 0:f2716e543d97 146 #define SX1272_MC1_IMPLICIT_HEADER_MODE_ON 0x04 // required for receive
dudmuck 0:f2716e543d97 147 #define SX1272_MC1_RX_PAYLOAD_CRCON 0x02
dudmuck 0:f2716e543d97 148 #define SX1272_MC1_LOW_DATA_RATE_OPTIMIZE 0x01 // mandated for SF11 and SF12
dudmuck 0:f2716e543d97 149 // transmit power configuration for RegPaConfig
dudmuck 0:f2716e543d97 150 #define SX1272_PAC_PA_SELECT_PA_BOOST 0x80
dudmuck 0:f2716e543d97 151 #define SX1272_PAC_PA_SELECT_RFIO_PIN 0x00
dudmuck 0:f2716e543d97 152
dudmuck 0:f2716e543d97 153
dudmuck 0:f2716e543d97 154 // sx1276 RegModemConfig1
dudmuck 0:f2716e543d97 155 #define SX1276_MC1_BW_125 0x70
dudmuck 0:f2716e543d97 156 #define SX1276_MC1_BW_250 0x80
dudmuck 0:f2716e543d97 157 #define SX1276_MC1_BW_500 0x90
dudmuck 0:f2716e543d97 158 #define SX1276_MC1_CR_4_5 0x02
dudmuck 0:f2716e543d97 159 #define SX1276_MC1_CR_4_6 0x04
dudmuck 0:f2716e543d97 160 #define SX1276_MC1_CR_4_7 0x06
dudmuck 0:f2716e543d97 161 #define SX1276_MC1_CR_4_8 0x08
dudmuck 0:f2716e543d97 162
dudmuck 0:f2716e543d97 163 #define SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01
dudmuck 0:f2716e543d97 164
dudmuck 0:f2716e543d97 165 // sx1276 RegModemConfig2
dudmuck 0:f2716e543d97 166 #define SX1276_MC2_RX_PAYLOAD_CRCON 0x04
dudmuck 0:f2716e543d97 167
dudmuck 0:f2716e543d97 168 // sx1276 RegModemConfig3
dudmuck 0:f2716e543d97 169 #define SX1276_MC3_LOW_DATA_RATE_OPTIMIZE 0x08
dudmuck 0:f2716e543d97 170 #define SX1276_MC3_AGCAUTO 0x04
dudmuck 0:f2716e543d97 171
dudmuck 0:f2716e543d97 172 // preamble for lora networks (nibbles swapped)
dudmuck 0:f2716e543d97 173 #define LORA_MAC_PREAMBLE 0x34
dudmuck 0:f2716e543d97 174
dudmuck 0:f2716e543d97 175 #define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1 0x0A
dudmuck 0:f2716e543d97 176 #ifdef CFG_sx1276_radio
dudmuck 0:f2716e543d97 177 #define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x70
dudmuck 0:f2716e543d97 178 #elif defined(CFG_sx1272_radio)
dudmuck 0:f2716e543d97 179 #define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x74
dudmuck 0:f2716e543d97 180 #endif
dudmuck 0:f2716e543d97 181
dudmuck 0:f2716e543d97 182
dudmuck 0:f2716e543d97 183
dudmuck 0:f2716e543d97 184 // ----------------------------------------
dudmuck 0:f2716e543d97 185 // Constants for radio registers
dudmuck 0:f2716e543d97 186 #define OPMODE_LORA 0x80
dudmuck 0:f2716e543d97 187 #define OPMODE_MASK 0x07
dudmuck 0:f2716e543d97 188 #define OPMODE_SLEEP 0x00
dudmuck 0:f2716e543d97 189 #define OPMODE_STANDBY 0x01
dudmuck 0:f2716e543d97 190 #define OPMODE_FSTX 0x02
dudmuck 0:f2716e543d97 191 #define OPMODE_TX 0x03
dudmuck 0:f2716e543d97 192 #define OPMODE_FSRX 0x04
dudmuck 0:f2716e543d97 193 #define OPMODE_RX 0x05
dudmuck 0:f2716e543d97 194 #define OPMODE_RX_SINGLE 0x06
dudmuck 0:f2716e543d97 195 #define OPMODE_CAD 0x07
dudmuck 0:f2716e543d97 196
dudmuck 0:f2716e543d97 197 // ----------------------------------------
dudmuck 0:f2716e543d97 198 // Bits masking the corresponding IRQs from the radio
dudmuck 0:f2716e543d97 199 #define IRQ_LORA_RXTOUT_MASK 0x80
dudmuck 0:f2716e543d97 200 #define IRQ_LORA_RXDONE_MASK 0x40
dudmuck 0:f2716e543d97 201 #define IRQ_LORA_CRCERR_MASK 0x20
dudmuck 0:f2716e543d97 202 #define IRQ_LORA_HEADER_MASK 0x10
dudmuck 0:f2716e543d97 203 #define IRQ_LORA_TXDONE_MASK 0x08
dudmuck 0:f2716e543d97 204 #define IRQ_LORA_CDDONE_MASK 0x04
dudmuck 0:f2716e543d97 205 #define IRQ_LORA_FHSSCH_MASK 0x02
dudmuck 0:f2716e543d97 206 #define IRQ_LORA_CDDETD_MASK 0x01
dudmuck 0:f2716e543d97 207
dudmuck 0:f2716e543d97 208 #define IRQ_FSK1_MODEREADY_MASK 0x80
dudmuck 0:f2716e543d97 209 #define IRQ_FSK1_RXREADY_MASK 0x40
dudmuck 0:f2716e543d97 210 #define IRQ_FSK1_TXREADY_MASK 0x20
dudmuck 0:f2716e543d97 211 #define IRQ_FSK1_PLLLOCK_MASK 0x10
dudmuck 0:f2716e543d97 212 #define IRQ_FSK1_RSSI_MASK 0x08
dudmuck 0:f2716e543d97 213 #define IRQ_FSK1_TIMEOUT_MASK 0x04
dudmuck 0:f2716e543d97 214 #define IRQ_FSK1_PREAMBLEDETECT_MASK 0x02
dudmuck 0:f2716e543d97 215 #define IRQ_FSK1_SYNCADDRESSMATCH_MASK 0x01
dudmuck 0:f2716e543d97 216 #define IRQ_FSK2_FIFOFULL_MASK 0x80
dudmuck 0:f2716e543d97 217 #define IRQ_FSK2_FIFOEMPTY_MASK 0x40
dudmuck 0:f2716e543d97 218 #define IRQ_FSK2_FIFOLEVEL_MASK 0x20
dudmuck 0:f2716e543d97 219 #define IRQ_FSK2_FIFOOVERRUN_MASK 0x10
dudmuck 0:f2716e543d97 220 #define IRQ_FSK2_PACKETSENT_MASK 0x08
dudmuck 0:f2716e543d97 221 #define IRQ_FSK2_PAYLOADREADY_MASK 0x04
dudmuck 0:f2716e543d97 222 #define IRQ_FSK2_CRCOK_MASK 0x02
dudmuck 0:f2716e543d97 223 #define IRQ_FSK2_LOWBAT_MASK 0x01
dudmuck 0:f2716e543d97 224
dudmuck 0:f2716e543d97 225 // ----------------------------------------
dudmuck 0:f2716e543d97 226 // DIO function mappings D0D1D2D3
dudmuck 0:f2716e543d97 227 #define MAP_DIO0_LORA_RXDONE 0x00 // 00------
dudmuck 0:f2716e543d97 228 #define MAP_DIO0_LORA_TXDONE 0x40 // 01------
dudmuck 0:f2716e543d97 229 #define MAP_DIO1_LORA_RXTOUT 0x00 // --00----
dudmuck 0:f2716e543d97 230 #define MAP_DIO1_LORA_NOP 0x30 // --11----
dudmuck 4:1a9a62cf220f 231 #define MAP_DIO2_LORA_NOP 0x0c // ----11--
dudmuck 0:f2716e543d97 232
dudmuck 0:f2716e543d97 233 #define MAP_DIO0_FSK_READY 0x00 // 00------ (packet sent / payload ready)
dudmuck 0:f2716e543d97 234 #define MAP_DIO1_FSK_NOP 0x30 // --11----
dudmuck 0:f2716e543d97 235 #define MAP_DIO2_FSK_TXNOP 0x04 // ----01--
dudmuck 0:f2716e543d97 236 #define MAP_DIO2_FSK_TIMEOUT 0x08 // ----10--
dudmuck 0:f2716e543d97 237
dudmuck 0:f2716e543d97 238
dudmuck 0:f2716e543d97 239 // FSK IMAGECAL defines
dudmuck 0:f2716e543d97 240 #define RF_IMAGECAL_AUTOIMAGECAL_MASK 0x7F
dudmuck 0:f2716e543d97 241 #define RF_IMAGECAL_AUTOIMAGECAL_ON 0x80
dudmuck 0:f2716e543d97 242 #define RF_IMAGECAL_AUTOIMAGECAL_OFF 0x00 // Default
dudmuck 0:f2716e543d97 243
dudmuck 0:f2716e543d97 244 #define RF_IMAGECAL_IMAGECAL_MASK 0xBF
dudmuck 0:f2716e543d97 245 #define RF_IMAGECAL_IMAGECAL_START 0x40
dudmuck 0:f2716e543d97 246
dudmuck 0:f2716e543d97 247 #define RF_IMAGECAL_IMAGECAL_RUNNING 0x20
dudmuck 0:f2716e543d97 248 #define RF_IMAGECAL_IMAGECAL_DONE 0x00 // Default
dudmuck 0:f2716e543d97 249
dudmuck 0:f2716e543d97 250
dudmuck 0:f2716e543d97 251 // RADIO STATE
dudmuck 0:f2716e543d97 252 // (initialized by radio_init(), used by radio_rand1())
dudmuck 0:f2716e543d97 253 static u1_t randbuf[16];
dudmuck 0:f2716e543d97 254 static u1_t PaSelect;
dudmuck 0:f2716e543d97 255
dudmuck 0:f2716e543d97 256 #ifdef CFG_sx1276_radio
dudmuck 0:f2716e543d97 257 #define LNA_RX_GAIN (0x20|0x1)
dudmuck 0:f2716e543d97 258 #elif defined(CFG_sx1272_radio)
dudmuck 0:f2716e543d97 259 #define LNA_RX_GAIN (0x20|0x03)
dudmuck 0:f2716e543d97 260 #else
dudmuck 0:f2716e543d97 261 #error Missing CFG_sx1272_radio/CFG_sx1276_radio
dudmuck 0:f2716e543d97 262 #endif
dudmuck 0:f2716e543d97 263
dudmuck 0:f2716e543d97 264
dudmuck 0:f2716e543d97 265 static void writeReg (u1_t addr, u1_t data ) {
dudmuck 0:f2716e543d97 266 hal_pin_nss(0);
dudmuck 0:f2716e543d97 267 hal_spi(addr | 0x80);
dudmuck 0:f2716e543d97 268 hal_spi(data);
dudmuck 0:f2716e543d97 269 hal_pin_nss(1);
dudmuck 0:f2716e543d97 270 }
dudmuck 0:f2716e543d97 271
dudmuck 0:f2716e543d97 272 static u1_t readReg (u1_t addr) {
dudmuck 0:f2716e543d97 273 hal_pin_nss(0);
dudmuck 0:f2716e543d97 274 hal_spi(addr & 0x7F);
dudmuck 0:f2716e543d97 275 u1_t val = hal_spi(0x00);
dudmuck 0:f2716e543d97 276 hal_pin_nss(1);
dudmuck 0:f2716e543d97 277 return val;
dudmuck 0:f2716e543d97 278 }
dudmuck 0:f2716e543d97 279
dudmuck 0:f2716e543d97 280 static void writeBuf (u1_t addr, xref2u1_t buf, u1_t len) {
dudmuck 0:f2716e543d97 281 hal_pin_nss(0);
dudmuck 0:f2716e543d97 282 hal_spi(addr | 0x80);
dudmuck 0:f2716e543d97 283 for (u1_t i=0; i<len; i++) {
dudmuck 0:f2716e543d97 284 hal_spi(buf[i]);
dudmuck 0:f2716e543d97 285 }
dudmuck 0:f2716e543d97 286 hal_pin_nss(1);
dudmuck 0:f2716e543d97 287 }
dudmuck 0:f2716e543d97 288
dudmuck 0:f2716e543d97 289 static void readBuf (u1_t addr, xref2u1_t buf, u1_t len) {
dudmuck 0:f2716e543d97 290 hal_pin_nss(0);
dudmuck 0:f2716e543d97 291 hal_spi(addr & 0x7F);
dudmuck 0:f2716e543d97 292 for (u1_t i=0; i<len; i++) {
dudmuck 0:f2716e543d97 293 buf[i] = hal_spi(0x00);
dudmuck 0:f2716e543d97 294 }
dudmuck 0:f2716e543d97 295 hal_pin_nss(1);
dudmuck 0:f2716e543d97 296 }
dudmuck 0:f2716e543d97 297
dudmuck 4:1a9a62cf220f 298 static void opmode (u1_t mode) {
dudmuck 0:f2716e543d97 299 hal_opmode(mode, PaSelect);
dudmuck 0:f2716e543d97 300 writeReg(RegOpMode, (readReg(RegOpMode) & ~OPMODE_MASK) | mode);
dudmuck 0:f2716e543d97 301 }
dudmuck 0:f2716e543d97 302
dudmuck 0:f2716e543d97 303 static void opmodeLora() {
dudmuck 0:f2716e543d97 304 u1_t u = OPMODE_LORA;
dudmuck 0:f2716e543d97 305 #ifdef CFG_sx1276_radio
dudmuck 0:f2716e543d97 306 u |= 0x8; // TBD: sx1276 high freq
dudmuck 0:f2716e543d97 307 #endif
dudmuck 0:f2716e543d97 308 writeReg(RegOpMode, u);
dudmuck 0:f2716e543d97 309 }
dudmuck 0:f2716e543d97 310
dudmuck 0:f2716e543d97 311 static void opmodeFSK() {
dudmuck 0:f2716e543d97 312 u1_t u = 0;
dudmuck 0:f2716e543d97 313 #ifdef CFG_sx1276_radio
dudmuck 0:f2716e543d97 314 u |= 0x8; // TBD: sx1276 high freq
dudmuck 0:f2716e543d97 315 #endif
dudmuck 0:f2716e543d97 316 writeReg(RegOpMode, u);
dudmuck 0:f2716e543d97 317 }
dudmuck 0:f2716e543d97 318
dudmuck 0:f2716e543d97 319 // configure LoRa modem (cfg1, cfg2)
dudmuck 0:f2716e543d97 320 static void configLoraModem () {
dudmuck 0:f2716e543d97 321 sf_t sf = getSf(LMIC.rps);
dudmuck 0:f2716e543d97 322
dudmuck 0:f2716e543d97 323 #ifdef CFG_sx1276_radio
dudmuck 0:f2716e543d97 324 u1_t mc1 = 0, mc2 = 0, mc3 = 0;
dudmuck 0:f2716e543d97 325
dudmuck 0:f2716e543d97 326 switch (getBw(LMIC.rps)) {
dudmuck 0:f2716e543d97 327 case BW125: mc1 |= SX1276_MC1_BW_125; break;
dudmuck 0:f2716e543d97 328 case BW250: mc1 |= SX1276_MC1_BW_250; break;
dudmuck 0:f2716e543d97 329 case BW500: mc1 |= SX1276_MC1_BW_500; break;
dudmuck 0:f2716e543d97 330 default:
dudmuck 0:f2716e543d97 331 ASSERT(0);
dudmuck 0:f2716e543d97 332 }
dudmuck 0:f2716e543d97 333 switch( getCr(LMIC.rps) ) {
dudmuck 0:f2716e543d97 334 case CR_4_5: mc1 |= SX1276_MC1_CR_4_5; break;
dudmuck 0:f2716e543d97 335 case CR_4_6: mc1 |= SX1276_MC1_CR_4_6; break;
dudmuck 0:f2716e543d97 336 case CR_4_7: mc1 |= SX1276_MC1_CR_4_7; break;
dudmuck 0:f2716e543d97 337 case CR_4_8: mc1 |= SX1276_MC1_CR_4_8; break;
dudmuck 0:f2716e543d97 338 default:
dudmuck 0:f2716e543d97 339 ASSERT(0);
dudmuck 0:f2716e543d97 340 }
dudmuck 0:f2716e543d97 341
dudmuck 0:f2716e543d97 342 if (getIh(LMIC.rps)) {
dudmuck 0:f2716e543d97 343 mc1 |= SX1276_MC1_IMPLICIT_HEADER_MODE_ON;
dudmuck 0:f2716e543d97 344 writeReg(LORARegPayloadLength, getIh(LMIC.rps)); // required length
dudmuck 0:f2716e543d97 345 }
dudmuck 0:f2716e543d97 346 // set ModemConfig1
dudmuck 0:f2716e543d97 347 writeReg(LORARegModemConfig1, mc1);
dudmuck 0:f2716e543d97 348
dudmuck 0:f2716e543d97 349 mc2 = (SX1272_MC2_SF7 + ((sf-1)<<4));
dudmuck 0:f2716e543d97 350 if (getNocrc(LMIC.rps) == 0) {
dudmuck 0:f2716e543d97 351 mc2 |= SX1276_MC2_RX_PAYLOAD_CRCON;
dudmuck 0:f2716e543d97 352 }
dudmuck 0:f2716e543d97 353 writeReg(LORARegModemConfig2, mc2);
dudmuck 0:f2716e543d97 354
dudmuck 0:f2716e543d97 355 mc3 = SX1276_MC3_AGCAUTO;
dudmuck 0:f2716e543d97 356 if ((sf == SF11 || sf == SF12) && getBw(LMIC.rps) == BW125) {
dudmuck 0:f2716e543d97 357 mc3 |= SX1276_MC3_LOW_DATA_RATE_OPTIMIZE;
dudmuck 0:f2716e543d97 358 }
dudmuck 0:f2716e543d97 359 writeReg(LORARegModemConfig3, mc3);
dudmuck 0:f2716e543d97 360 #elif defined(CFG_sx1272_radio)
dudmuck 0:f2716e543d97 361 u1_t mc1 = (getBw(LMIC.rps)<<6);
dudmuck 0:f2716e543d97 362
dudmuck 0:f2716e543d97 363 switch( getCr(LMIC.rps) ) {
dudmuck 0:f2716e543d97 364 case CR_4_5: mc1 |= SX1272_MC1_CR_4_5; break;
dudmuck 0:f2716e543d97 365 case CR_4_6: mc1 |= SX1272_MC1_CR_4_6; break;
dudmuck 0:f2716e543d97 366 case CR_4_7: mc1 |= SX1272_MC1_CR_4_7; break;
dudmuck 0:f2716e543d97 367 case CR_4_8: mc1 |= SX1272_MC1_CR_4_8; break;
dudmuck 0:f2716e543d97 368 }
dudmuck 0:f2716e543d97 369
dudmuck 0:f2716e543d97 370 if ((sf == SF11 || sf == SF12) && getBw(LMIC.rps) == BW125) {
dudmuck 0:f2716e543d97 371 mc1 |= SX1272_MC1_LOW_DATA_RATE_OPTIMIZE;
dudmuck 0:f2716e543d97 372 }
dudmuck 0:f2716e543d97 373
dudmuck 0:f2716e543d97 374 if (getNocrc(LMIC.rps) == 0) {
dudmuck 0:f2716e543d97 375 mc1 |= SX1272_MC1_RX_PAYLOAD_CRCON;
dudmuck 0:f2716e543d97 376 }
dudmuck 0:f2716e543d97 377
dudmuck 0:f2716e543d97 378 if (getIh(LMIC.rps)) {
dudmuck 0:f2716e543d97 379 mc1 |= SX1272_MC1_IMPLICIT_HEADER_MODE_ON;
dudmuck 0:f2716e543d97 380 writeReg(LORARegPayloadLength, getIh(LMIC.rps)); // required length
dudmuck 0:f2716e543d97 381 }
dudmuck 0:f2716e543d97 382 // set ModemConfig1
dudmuck 0:f2716e543d97 383 writeReg(LORARegModemConfig1, mc1);
dudmuck 0:f2716e543d97 384
dudmuck 0:f2716e543d97 385 // set ModemConfig2 (sf, AgcAutoOn=1 SymbTimeoutHi=00)
dudmuck 0:f2716e543d97 386 writeReg(LORARegModemConfig2, (SX1272_MC2_SF7 + ((sf-1)<<4)) | 0x04);
dudmuck 0:f2716e543d97 387 #else
dudmuck 0:f2716e543d97 388 #error Missing CFG_sx1272_radio/CFG_sx1276_radio
dudmuck 0:f2716e543d97 389 #endif /* CFG_sx1272_radio */
dudmuck 0:f2716e543d97 390 }
dudmuck 0:f2716e543d97 391
dudmuck 0:f2716e543d97 392 static void configChannel () {
dudmuck 0:f2716e543d97 393 // set frequency: FQ = (FRF * 32 Mhz) / (2 ^ 19)
dudmuck 0:f2716e543d97 394 u8_t frf = ((u8_t)LMIC.freq << 19) / 32000000;
dudmuck 0:f2716e543d97 395 writeReg(RegFrfMsb, (u1_t)(frf>>16));
dudmuck 0:f2716e543d97 396 writeReg(RegFrfMid, (u1_t)(frf>> 8));
dudmuck 0:f2716e543d97 397 writeReg(RegFrfLsb, (u1_t)(frf>> 0));
dudmuck 0:f2716e543d97 398 }
dudmuck 0:f2716e543d97 399
dudmuck 3:d87012f45bf6 400 DigitalOut pd2(PD_2); // power amplifier voltage control pin
dudmuck 0:f2716e543d97 401
dudmuck 8:0faa1bb768b5 402 /* pd2=0 pd2=1
dudmuck 8:0faa1bb768b5 403 op pab rfo rfo
dudmuck 8:0faa1bb768b5 404 0 4.6 18.5 27.0
dudmuck 8:0faa1bb768b5 405 1 5.6 21.1 28.1
dudmuck 8:0faa1bb768b5 406 2 6.7 23.3 29.1
dudmuck 8:0faa1bb768b5 407 3 7.7 25.3 30.1
dudmuck 8:0faa1bb768b5 408 4 8.8 26.2 30.7
dudmuck 8:0faa1bb768b5 409 5 9.8 27.3 31.2
dudmuck 8:0faa1bb768b5 410 6 10.7 28.1 31.6
dudmuck 8:0faa1bb768b5 411 7 11.7 28.6 32.2
dudmuck 8:0faa1bb768b5 412 8 12.8 29.2 32.4
dudmuck 8:0faa1bb768b5 413 9 13.7 29.9 32.9
dudmuck 8:0faa1bb768b5 414 10 14.7 30.5 33.1
dudmuck 8:0faa1bb768b5 415 11 15.6 30.8 33.4
dudmuck 8:0faa1bb768b5 416 12 16.4 30.9 33.6
dudmuck 8:0faa1bb768b5 417 13 17.1 31.0 33.7
dudmuck 8:0faa1bb768b5 418 14 17.8 31.1 33.7
dudmuck 8:0faa1bb768b5 419 15 18.4 31.1 33.7
dudmuck 8:0faa1bb768b5 420 */
dudmuck 8:0faa1bb768b5 421 // txpow: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
dudmuck 8:0faa1bb768b5 422 static const u1_t boost_table[20] = { 0, 0, 0, 0, 0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15 };
dudmuck 8:0faa1bb768b5 423
dudmuck 8:0faa1bb768b5 424 // txpow: 20 21 22 23 24 25 26 27 28 29 30
dudmuck 8:0faa1bb768b5 425 static const u1_t rfo_table[11] = { 1, 1, 1, 2, 2, 3, 4, 5, 6, 8, 9 };
dudmuck 8:0faa1bb768b5 426
dudmuck 0:f2716e543d97 427 static void configPower () {
dudmuck 0:f2716e543d97 428 #ifdef CFG_sx1276_radio
dudmuck 0:f2716e543d97 429 // no boost used for now
dudmuck 0:f2716e543d97 430 s1_t pw = (s1_t)LMIC.txpow;
dudmuck 0:f2716e543d97 431 if(pw >= 17) {
dudmuck 0:f2716e543d97 432 pw = 15;
dudmuck 0:f2716e543d97 433 } else if(pw < 2) {
dudmuck 0:f2716e543d97 434 pw = 2;
dudmuck 0:f2716e543d97 435 }
dudmuck 0:f2716e543d97 436 // check board type for BOOST pin
dudmuck 0:f2716e543d97 437 writeReg(RegPaConfig, (u1_t)(0x80|(pw&0xf)));
dudmuck 0:f2716e543d97 438 writeReg(RegPaDac, readReg(RegPaDac)|0x4);
dudmuck 0:f2716e543d97 439
dudmuck 0:f2716e543d97 440 #elif defined(CFG_sx1272_radio)
dudmuck 8:0faa1bb768b5 441
dudmuck 2:edb5d1f3deeb 442 /* NA-mote TX power config: */
dudmuck 8:0faa1bb768b5 443 if (LMIC.txpow > 19) {
dudmuck 2:edb5d1f3deeb 444 PaSelect = 0x00; // use RFO
dudmuck 8:0faa1bb768b5 445 writeReg(RegPaConfig, PaSelect | rfo_table[LMIC.txpow-20]);
dudmuck 8:0faa1bb768b5 446 pd2 = 0;
dudmuck 2:edb5d1f3deeb 447 } else {
dudmuck 2:edb5d1f3deeb 448 PaSelect = 0x80; // use PA_BOOST
dudmuck 8:0faa1bb768b5 449 writeReg(RegPaConfig, PaSelect | boost_table[LMIC.txpow]);
dudmuck 0:f2716e543d97 450 }
dudmuck 2:edb5d1f3deeb 451
dudmuck 0:f2716e543d97 452 #else
dudmuck 0:f2716e543d97 453 #error Missing CFG_sx1272_radio/CFG_sx1276_radio
dudmuck 0:f2716e543d97 454 #endif /* CFG_sx1272_radio */
dudmuck 0:f2716e543d97 455 }
dudmuck 0:f2716e543d97 456
dudmuck 0:f2716e543d97 457 static void txfsk () {
dudmuck 0:f2716e543d97 458 // select FSK modem (from sleep mode)
dudmuck 0:f2716e543d97 459 writeReg(RegOpMode, 0x10); // FSK, BT=0.5
dudmuck 0:f2716e543d97 460 ASSERT(readReg(RegOpMode) == 0x10);
dudmuck 0:f2716e543d97 461 // enter standby mode (required for FIFO loading))
dudmuck 0:f2716e543d97 462 opmode(OPMODE_STANDBY);
dudmuck 0:f2716e543d97 463 // set bitrate
dudmuck 0:f2716e543d97 464 writeReg(FSKRegBitrateMsb, 0x02); // 50kbps
dudmuck 0:f2716e543d97 465 writeReg(FSKRegBitrateLsb, 0x80);
dudmuck 0:f2716e543d97 466 // set frequency deviation
dudmuck 0:f2716e543d97 467 writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz
dudmuck 0:f2716e543d97 468 writeReg(FSKRegFdevLsb, 0x99);
dudmuck 0:f2716e543d97 469 // frame and packet handler settings
dudmuck 0:f2716e543d97 470 writeReg(FSKRegPreambleMsb, 0x00);
dudmuck 0:f2716e543d97 471 writeReg(FSKRegPreambleLsb, 0x05);
dudmuck 0:f2716e543d97 472 writeReg(FSKRegSyncConfig, 0x12);
dudmuck 0:f2716e543d97 473 writeReg(FSKRegPacketConfig1, 0xD0);
dudmuck 0:f2716e543d97 474 writeReg(FSKRegPacketConfig2, 0x40);
dudmuck 0:f2716e543d97 475 writeReg(FSKRegSyncValue1, 0xC1);
dudmuck 0:f2716e543d97 476 writeReg(FSKRegSyncValue2, 0x94);
dudmuck 0:f2716e543d97 477 writeReg(FSKRegSyncValue3, 0xC1);
dudmuck 0:f2716e543d97 478 // configure frequency
dudmuck 0:f2716e543d97 479 configChannel();
dudmuck 0:f2716e543d97 480 // configure output power
dudmuck 0:f2716e543d97 481 configPower();
dudmuck 0:f2716e543d97 482
dudmuck 0:f2716e543d97 483 // set the IRQ mapping DIO0=PacketSent DIO1=NOP DIO2=NOP
dudmuck 0:f2716e543d97 484 writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TXNOP);
dudmuck 0:f2716e543d97 485
dudmuck 0:f2716e543d97 486 // initialize the payload size and address pointers
dudmuck 0:f2716e543d97 487 writeReg(FSKRegPayloadLength, LMIC.dataLen+1); // (insert length byte into payload))
dudmuck 0:f2716e543d97 488
dudmuck 0:f2716e543d97 489 // download length byte and buffer to the radio FIFO
dudmuck 0:f2716e543d97 490 writeReg(RegFifo, LMIC.dataLen);
dudmuck 0:f2716e543d97 491 writeBuf(RegFifo, LMIC.frame, LMIC.dataLen);
dudmuck 0:f2716e543d97 492
dudmuck 0:f2716e543d97 493 // enable antenna switch for TX
dudmuck 2:edb5d1f3deeb 494 //hal_pin_rxtx(1); usint hal_opmode
dudmuck 0:f2716e543d97 495
dudmuck 0:f2716e543d97 496 // now we actually start the transmission
dudmuck 0:f2716e543d97 497 opmode(OPMODE_TX);
dudmuck 0:f2716e543d97 498 }
dudmuck 0:f2716e543d97 499
dudmuck 0:f2716e543d97 500 static void txlora () {
dudmuck 0:f2716e543d97 501 // select LoRa modem (from sleep mode)
dudmuck 0:f2716e543d97 502 //writeReg(RegOpMode, OPMODE_LORA);
dudmuck 0:f2716e543d97 503 opmodeLora();
dudmuck 0:f2716e543d97 504 ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0);
dudmuck 0:f2716e543d97 505
dudmuck 0:f2716e543d97 506 // enter standby mode (required for FIFO loading))
dudmuck 0:f2716e543d97 507 opmode(OPMODE_STANDBY);
dudmuck 0:f2716e543d97 508 // configure LoRa modem (cfg1, cfg2)
dudmuck 0:f2716e543d97 509 configLoraModem();
dudmuck 0:f2716e543d97 510 // configure frequency
dudmuck 0:f2716e543d97 511 configChannel();
dudmuck 0:f2716e543d97 512 // configure output power
dudmuck 0:f2716e543d97 513 writeReg(RegPaRamp, (readReg(RegPaRamp) & 0xF0) | 0x08); // set PA ramp-up time 50 uSec
dudmuck 0:f2716e543d97 514 configPower();
dudmuck 0:f2716e543d97 515 // set sync word
dudmuck 0:f2716e543d97 516 writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE);
dudmuck 0:f2716e543d97 517
dudmuck 0:f2716e543d97 518 // set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP
dudmuck 0:f2716e543d97 519 writeReg(RegDioMapping1, MAP_DIO0_LORA_TXDONE|MAP_DIO1_LORA_NOP|MAP_DIO2_LORA_NOP);
dudmuck 0:f2716e543d97 520 // clear all radio IRQ flags
dudmuck 0:f2716e543d97 521 writeReg(LORARegIrqFlags, 0xFF);
dudmuck 0:f2716e543d97 522 // mask all IRQs but TxDone
dudmuck 0:f2716e543d97 523 writeReg(LORARegIrqFlagsMask, ~IRQ_LORA_TXDONE_MASK);
dudmuck 0:f2716e543d97 524
dudmuck 0:f2716e543d97 525 // initialize the payload size and address pointers
dudmuck 0:f2716e543d97 526 writeReg(LORARegFifoTxBaseAddr, 0x00);
dudmuck 0:f2716e543d97 527 writeReg(LORARegFifoAddrPtr, 0x00);
dudmuck 0:f2716e543d97 528 writeReg(LORARegPayloadLength, LMIC.dataLen);
dudmuck 0:f2716e543d97 529
dudmuck 0:f2716e543d97 530 // download buffer to the radio FIFO
dudmuck 0:f2716e543d97 531 writeBuf(RegFifo, LMIC.frame, LMIC.dataLen);
dudmuck 0:f2716e543d97 532
dudmuck 0:f2716e543d97 533 // enable antenna switch for TX
dudmuck 2:edb5d1f3deeb 534 //hal_pin_rxtx(1); using hal_opmode
dudmuck 0:f2716e543d97 535
dudmuck 0:f2716e543d97 536 // now we actually start the transmission
dudmuck 0:f2716e543d97 537 opmode(OPMODE_TX);
dudmuck 0:f2716e543d97 538 }
dudmuck 0:f2716e543d97 539
dudmuck 0:f2716e543d97 540 // start transmitter (buf=LMIC.frame, len=LMIC.dataLen)
dudmuck 0:f2716e543d97 541 static void starttx () {
dudmuck 0:f2716e543d97 542 ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP );
dudmuck 0:f2716e543d97 543 if(getSf(LMIC.rps) == FSK) { // FSK modem
dudmuck 0:f2716e543d97 544 txfsk();
dudmuck 0:f2716e543d97 545 } else { // LoRa modem
dudmuck 0:f2716e543d97 546 txlora();
dudmuck 0:f2716e543d97 547 }
dudmuck 0:f2716e543d97 548 // the radio will go back to STANDBY mode as soon as the TX is finished
dudmuck 0:f2716e543d97 549 // the corresponding IRQ will inform us about completion.
dudmuck 0:f2716e543d97 550 }
dudmuck 0:f2716e543d97 551
dudmuck 0:f2716e543d97 552 enum { RXMODE_SINGLE, RXMODE_SCAN, RXMODE_RSSI };
dudmuck 0:f2716e543d97 553
dudmuck 0:f2716e543d97 554 static const u1_t rxlorairqmask[] = {
dudmuck 0:f2716e543d97 555 [RXMODE_SINGLE] = IRQ_LORA_RXDONE_MASK|IRQ_LORA_RXTOUT_MASK,
dudmuck 0:f2716e543d97 556 [RXMODE_SCAN] = IRQ_LORA_RXDONE_MASK,
dudmuck 0:f2716e543d97 557 [RXMODE_RSSI] = 0x00,
dudmuck 0:f2716e543d97 558 };
dudmuck 0:f2716e543d97 559
dudmuck 0:f2716e543d97 560 // start LoRa receiver (time=LMIC.rxtime, timeout=LMIC.rxsyms, result=LMIC.frame[LMIC.dataLen])
dudmuck 0:f2716e543d97 561 static void rxlora (u1_t rxmode) {
dudmuck 0:f2716e543d97 562 // select LoRa modem (from sleep mode)
dudmuck 0:f2716e543d97 563 opmodeLora();
dudmuck 0:f2716e543d97 564 ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0);
dudmuck 0:f2716e543d97 565 // enter standby mode (warm up))
dudmuck 0:f2716e543d97 566 opmode(OPMODE_STANDBY);
dudmuck 0:f2716e543d97 567 // don't use MAC settings at startup
dudmuck 0:f2716e543d97 568 if(rxmode == RXMODE_RSSI) { // use fixed settings for rssi scan
dudmuck 0:f2716e543d97 569 writeReg(LORARegModemConfig1, RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1);
dudmuck 0:f2716e543d97 570 writeReg(LORARegModemConfig2, RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2);
dudmuck 0:f2716e543d97 571 } else { // single or continuous rx mode
dudmuck 0:f2716e543d97 572 // configure LoRa modem (cfg1, cfg2)
dudmuck 0:f2716e543d97 573 configLoraModem();
dudmuck 0:f2716e543d97 574 // configure frequency
dudmuck 0:f2716e543d97 575 configChannel();
dudmuck 0:f2716e543d97 576 }
dudmuck 0:f2716e543d97 577 // set LNA gain
dudmuck 0:f2716e543d97 578 writeReg(RegLna, LNA_RX_GAIN);
dudmuck 0:f2716e543d97 579 // set max payload size
dudmuck 0:f2716e543d97 580 writeReg(LORARegPayloadMaxLength, 64);
dudmuck 0:f2716e543d97 581 // use inverted I/Q signal (prevent mote-to-mote communication)
dudmuck 0:f2716e543d97 582 writeReg(LORARegInvertIQ, readReg(LORARegInvertIQ)|(1<<6));
dudmuck 0:f2716e543d97 583 // set symbol timeout (for single rx)
dudmuck 0:f2716e543d97 584 writeReg(LORARegSymbTimeoutLsb, LMIC.rxsyms);
dudmuck 0:f2716e543d97 585 // set sync word
dudmuck 0:f2716e543d97 586 writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE);
dudmuck 0:f2716e543d97 587
dudmuck 0:f2716e543d97 588 // configure DIO mapping DIO0=RxDone DIO1=RxTout DIO2=NOP
dudmuck 0:f2716e543d97 589 writeReg(RegDioMapping1, MAP_DIO0_LORA_RXDONE|MAP_DIO1_LORA_RXTOUT|MAP_DIO2_LORA_NOP);
dudmuck 0:f2716e543d97 590 // clear all radio IRQ flags
dudmuck 0:f2716e543d97 591 writeReg(LORARegIrqFlags, 0xFF);
dudmuck 0:f2716e543d97 592 // enable required radio IRQs
dudmuck 0:f2716e543d97 593 writeReg(LORARegIrqFlagsMask, ~rxlorairqmask[rxmode]);
dudmuck 0:f2716e543d97 594
dudmuck 0:f2716e543d97 595 // enable antenna switch for RX
dudmuck 2:edb5d1f3deeb 596 //hal_pin_rxtx(0); using hal_opmode
dudmuck 0:f2716e543d97 597
dudmuck 0:f2716e543d97 598 // now instruct the radio to receive
dudmuck 0:f2716e543d97 599 if (rxmode == RXMODE_SINGLE) { // single rx
dudmuck 0:f2716e543d97 600 hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
dudmuck 0:f2716e543d97 601 opmode(OPMODE_RX_SINGLE);
dudmuck 0:f2716e543d97 602 } else { // continous rx (scan or rssi)
dudmuck 0:f2716e543d97 603 opmode(OPMODE_RX);
dudmuck 0:f2716e543d97 604 }
dudmuck 0:f2716e543d97 605 }
dudmuck 0:f2716e543d97 606
dudmuck 0:f2716e543d97 607 static void rxfsk (u1_t rxmode) {
dudmuck 0:f2716e543d97 608 // only single rx (no continuous scanning, no noise sampling)
dudmuck 0:f2716e543d97 609 ASSERT( rxmode == RXMODE_SINGLE );
dudmuck 0:f2716e543d97 610 // select FSK modem (from sleep mode)
dudmuck 0:f2716e543d97 611 //writeReg(RegOpMode, 0x00); // (not LoRa)
dudmuck 0:f2716e543d97 612 opmodeFSK();
dudmuck 0:f2716e543d97 613 ASSERT((readReg(RegOpMode) & OPMODE_LORA) == 0);
dudmuck 0:f2716e543d97 614 // enter standby mode (warm up))
dudmuck 0:f2716e543d97 615 opmode(OPMODE_STANDBY);
dudmuck 0:f2716e543d97 616 // configure frequency
dudmuck 0:f2716e543d97 617 configChannel();
dudmuck 0:f2716e543d97 618 // set LNA gain
dudmuck 0:f2716e543d97 619 //writeReg(RegLna, 0x20|0x03); // max gain, boost enable
dudmuck 0:f2716e543d97 620 writeReg(RegLna, LNA_RX_GAIN);
dudmuck 0:f2716e543d97 621 // configure receiver
dudmuck 0:f2716e543d97 622 writeReg(FSKRegRxConfig, 0x1E); // AFC auto, AGC, trigger on preamble?!?
dudmuck 0:f2716e543d97 623 // set receiver bandwidth
dudmuck 0:f2716e543d97 624 writeReg(FSKRegRxBw, 0x0B); // 50kHz SSb
dudmuck 0:f2716e543d97 625 // set AFC bandwidth
dudmuck 0:f2716e543d97 626 writeReg(FSKRegAfcBw, 0x12); // 83.3kHz SSB
dudmuck 0:f2716e543d97 627 // set preamble detection
dudmuck 0:f2716e543d97 628 writeReg(FSKRegPreambleDetect, 0xAA); // enable, 2 bytes, 10 chip errors
dudmuck 0:f2716e543d97 629 // set sync config
dudmuck 0:f2716e543d97 630 writeReg(FSKRegSyncConfig, 0x12); // no auto restart, preamble 0xAA, enable, fill FIFO, 3 bytes sync
dudmuck 0:f2716e543d97 631 // set packet config
dudmuck 0:f2716e543d97 632 writeReg(FSKRegPacketConfig1, 0xD8); // var-length, whitening, crc, no auto-clear, no adr filter
dudmuck 0:f2716e543d97 633 writeReg(FSKRegPacketConfig2, 0x40); // packet mode
dudmuck 0:f2716e543d97 634 // set sync value
dudmuck 0:f2716e543d97 635 writeReg(FSKRegSyncValue1, 0xC1);
dudmuck 0:f2716e543d97 636 writeReg(FSKRegSyncValue2, 0x94);
dudmuck 0:f2716e543d97 637 writeReg(FSKRegSyncValue3, 0xC1);
dudmuck 0:f2716e543d97 638 // set preamble timeout
dudmuck 0:f2716e543d97 639 writeReg(FSKRegRxTimeout2, 0xFF);//(LMIC.rxsyms+1)/2);
dudmuck 0:f2716e543d97 640 // set bitrate
dudmuck 0:f2716e543d97 641 writeReg(FSKRegBitrateMsb, 0x02); // 50kbps
dudmuck 0:f2716e543d97 642 writeReg(FSKRegBitrateLsb, 0x80);
dudmuck 0:f2716e543d97 643 // set frequency deviation
dudmuck 0:f2716e543d97 644 writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz
dudmuck 0:f2716e543d97 645 writeReg(FSKRegFdevLsb, 0x99);
dudmuck 0:f2716e543d97 646
dudmuck 0:f2716e543d97 647 // configure DIO mapping DIO0=PayloadReady DIO1=NOP DIO2=TimeOut
dudmuck 0:f2716e543d97 648 writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TIMEOUT);
dudmuck 0:f2716e543d97 649
dudmuck 0:f2716e543d97 650 // enable antenna switch for RX
dudmuck 2:edb5d1f3deeb 651 //hal_pin_rxtx(0); using hal_opmode
dudmuck 0:f2716e543d97 652
dudmuck 0:f2716e543d97 653 // now instruct the radio to receive
dudmuck 0:f2716e543d97 654 hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
dudmuck 0:f2716e543d97 655 opmode(OPMODE_RX); // no single rx mode available in FSK
dudmuck 0:f2716e543d97 656 }
dudmuck 0:f2716e543d97 657
dudmuck 0:f2716e543d97 658 static void startrx (u1_t rxmode) {
dudmuck 0:f2716e543d97 659 ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP );
dudmuck 0:f2716e543d97 660 if(getSf(LMIC.rps) == FSK) { // FSK modem
dudmuck 0:f2716e543d97 661 rxfsk(rxmode);
dudmuck 0:f2716e543d97 662 } else { // LoRa modem
dudmuck 0:f2716e543d97 663 rxlora(rxmode);
dudmuck 0:f2716e543d97 664 }
dudmuck 0:f2716e543d97 665 // the radio will go back to STANDBY mode as soon as the RX is finished
dudmuck 0:f2716e543d97 666 // or timed out, and the corresponding IRQ will inform us about completion.
dudmuck 0:f2716e543d97 667 }
dudmuck 0:f2716e543d97 668
dudmuck 0:f2716e543d97 669 // get random seed from wideband noise rssi
dudmuck 0:f2716e543d97 670 void radio_init () {
dudmuck 0:f2716e543d97 671 hal_disableIRQs();
dudmuck 0:f2716e543d97 672
dudmuck 0:f2716e543d97 673 // manually reset radio
dudmuck 0:f2716e543d97 674 #ifdef CFG_sx1276_radio
dudmuck 0:f2716e543d97 675 hal_pin_rst(0); // drive RST pin low
dudmuck 0:f2716e543d97 676 #else
dudmuck 0:f2716e543d97 677 hal_pin_rst(1); // drive RST pin high
dudmuck 0:f2716e543d97 678 #endif
dudmuck 0:f2716e543d97 679 hal_waitUntil(os_getTime()+ms2osticks(1)); // wait >100us
dudmuck 0:f2716e543d97 680 hal_pin_rst(2); // configure RST pin floating!
dudmuck 0:f2716e543d97 681 hal_waitUntil(os_getTime()+ms2osticks(5)); // wait 5ms
dudmuck 0:f2716e543d97 682
dudmuck 0:f2716e543d97 683 opmode(OPMODE_SLEEP);
dudmuck 0:f2716e543d97 684
dudmuck 0:f2716e543d97 685 // some sanity checks, e.g., read version number
dudmuck 0:f2716e543d97 686 u1_t v = readReg(RegVersion);
dudmuck 0:f2716e543d97 687 #ifdef CFG_sx1276_radio
dudmuck 0:f2716e543d97 688 ASSERT(v == 0x12 );
dudmuck 0:f2716e543d97 689 #elif defined(CFG_sx1272_radio)
dudmuck 0:f2716e543d97 690 ASSERT(v == 0x22);
dudmuck 0:f2716e543d97 691 #else
dudmuck 0:f2716e543d97 692 #error Missing CFG_sx1272_radio/CFG_sx1276_radio
dudmuck 0:f2716e543d97 693 #endif
dudmuck 0:f2716e543d97 694 // seed 15-byte randomness via noise rssi
dudmuck 0:f2716e543d97 695 rxlora(RXMODE_RSSI);
dudmuck 0:f2716e543d97 696 while( (readReg(RegOpMode) & OPMODE_MASK) != OPMODE_RX ); // continuous rx
dudmuck 0:f2716e543d97 697 for(int i=1; i<16; i++) {
dudmuck 0:f2716e543d97 698 for(int j=0; j<8; j++) {
dudmuck 0:f2716e543d97 699 u1_t b; // wait for two non-identical subsequent least-significant bits
dudmuck 0:f2716e543d97 700 while( (b = readReg(LORARegRssiWideband) & 0x01) == (readReg(LORARegRssiWideband) & 0x01) );
dudmuck 0:f2716e543d97 701 randbuf[i] = (randbuf[i] << 1) | b;
dudmuck 0:f2716e543d97 702 }
dudmuck 0:f2716e543d97 703 }
dudmuck 0:f2716e543d97 704 randbuf[0] = 16; // set initial index
dudmuck 0:f2716e543d97 705
dudmuck 0:f2716e543d97 706 #ifdef CFG_sx1276mb1_board
dudmuck 0:f2716e543d97 707 // chain calibration
dudmuck 0:f2716e543d97 708 writeReg(RegPaConfig, 0);
dudmuck 0:f2716e543d97 709
dudmuck 0:f2716e543d97 710 // Launch Rx chain calibration for LF band
dudmuck 0:f2716e543d97 711 writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START);
dudmuck 0:f2716e543d97 712 while((readReg(FSKRegImageCal)&RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING){ ; }
dudmuck 0:f2716e543d97 713
dudmuck 0:f2716e543d97 714 // Sets a Frequency in HF band
dudmuck 0:f2716e543d97 715 u4_t frf = 868000000;
dudmuck 0:f2716e543d97 716 writeReg(RegFrfMsb, (u1_t)(frf>>16));
dudmuck 0:f2716e543d97 717 writeReg(RegFrfMid, (u1_t)(frf>> 8));
dudmuck 0:f2716e543d97 718 writeReg(RegFrfLsb, (u1_t)(frf>> 0));
dudmuck 0:f2716e543d97 719
dudmuck 0:f2716e543d97 720 // Launch Rx chain calibration for HF band
dudmuck 0:f2716e543d97 721 writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START);
dudmuck 0:f2716e543d97 722 while((readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING) { ; }
dudmuck 0:f2716e543d97 723 #endif /* CFG_sx1276mb1_board */
dudmuck 0:f2716e543d97 724
dudmuck 0:f2716e543d97 725 /* SF12/500KHz RX improvement (0x1d/0x19 choice): must match setting of LORARegInvertIQ */
dudmuck 0:f2716e543d97 726 writeReg(LORARegTimingInvert, 0x19);
dudmuck 0:f2716e543d97 727
dudmuck 0:f2716e543d97 728 opmode(OPMODE_SLEEP);
dudmuck 0:f2716e543d97 729
dudmuck 0:f2716e543d97 730 hal_enableIRQs();
dudmuck 0:f2716e543d97 731 }
dudmuck 0:f2716e543d97 732
dudmuck 0:f2716e543d97 733 // return next random byte derived from seed buffer
dudmuck 0:f2716e543d97 734 // (buf[0] holds index of next byte to be returned)
dudmuck 0:f2716e543d97 735 u1_t radio_rand1 () {
dudmuck 0:f2716e543d97 736 u1_t i = randbuf[0];
dudmuck 0:f2716e543d97 737 ASSERT( i != 0 );
dudmuck 0:f2716e543d97 738 if( i==16 ) {
dudmuck 0:f2716e543d97 739 os_aes(AES_ENC, randbuf, 16); // encrypt seed with any key
dudmuck 0:f2716e543d97 740 i = 0;
dudmuck 0:f2716e543d97 741 }
dudmuck 0:f2716e543d97 742 u1_t v = randbuf[i++];
dudmuck 0:f2716e543d97 743 randbuf[0] = i;
dudmuck 0:f2716e543d97 744 return v;
dudmuck 0:f2716e543d97 745 }
dudmuck 0:f2716e543d97 746
dudmuck 0:f2716e543d97 747 u1_t radio_rssi () {
dudmuck 0:f2716e543d97 748 hal_disableIRQs();
dudmuck 0:f2716e543d97 749 u1_t r = readReg(LORARegRssiValue);
dudmuck 0:f2716e543d97 750 hal_enableIRQs();
dudmuck 0:f2716e543d97 751 return r;
dudmuck 0:f2716e543d97 752 }
dudmuck 0:f2716e543d97 753
dudmuck 0:f2716e543d97 754 static const u2_t LORA_RXDONE_FIXUP[] = {
dudmuck 0:f2716e543d97 755 [FSK] = us2osticks(0), // ( 0 ticks)
dudmuck 0:f2716e543d97 756 [SF7] = us2osticks(0), // ( 0 ticks)
dudmuck 0:f2716e543d97 757 [SF8] = us2osticks(1648), // ( 54 ticks)
dudmuck 0:f2716e543d97 758 [SF9] = us2osticks(3265), // ( 107 ticks)
dudmuck 0:f2716e543d97 759 [SF10] = us2osticks(7049), // ( 231 ticks)
dudmuck 0:f2716e543d97 760 [SF11] = us2osticks(13641), // ( 447 ticks)
dudmuck 0:f2716e543d97 761 [SF12] = us2osticks(31189), // (1022 ticks)
dudmuck 0:f2716e543d97 762 };
dudmuck 0:f2716e543d97 763
dudmuck 0:f2716e543d97 764 // called by hal ext IRQ handler
dudmuck 0:f2716e543d97 765 // (radio goes to stanby mode after tx/rx operations)
dudmuck 0:f2716e543d97 766 void radio_irq_handler (u1_t dio) {
dudmuck 0:f2716e543d97 767 ostime_t now = os_getTime();
dudmuck 0:f2716e543d97 768 if( (readReg(RegOpMode) & OPMODE_LORA) != 0) { // LORA modem
dudmuck 0:f2716e543d97 769 u1_t flags = readReg(LORARegIrqFlags);
dudmuck 0:f2716e543d97 770 if( flags & IRQ_LORA_TXDONE_MASK ) {
dudmuck 0:f2716e543d97 771 // save exact tx time
dudmuck 0:f2716e543d97 772 LMIC.txend = now - us2osticks(43); // TXDONE FIXUP
dudmuck 0:f2716e543d97 773 } else if( flags & IRQ_LORA_RXDONE_MASK ) {
dudmuck 0:f2716e543d97 774 // save exact rx time
dudmuck 0:f2716e543d97 775 if(getBw(LMIC.rps) == BW125) {
dudmuck 0:f2716e543d97 776 now -= LORA_RXDONE_FIXUP[getSf(LMIC.rps)];
dudmuck 0:f2716e543d97 777 }
dudmuck 0:f2716e543d97 778 LMIC.rxtime = now;
dudmuck 0:f2716e543d97 779 // read the PDU and inform the MAC that we received something
dudmuck 0:f2716e543d97 780 LMIC.dataLen = (readReg(LORARegModemConfig1) & SX1272_MC1_IMPLICIT_HEADER_MODE_ON) ?
dudmuck 0:f2716e543d97 781 readReg(LORARegPayloadLength) : readReg(LORARegRxNbBytes);
dudmuck 0:f2716e543d97 782 // set FIFO read address pointer
dudmuck 0:f2716e543d97 783 writeReg(LORARegFifoAddrPtr, readReg(LORARegFifoRxCurrentAddr));
dudmuck 0:f2716e543d97 784 // now read the FIFO
dudmuck 0:f2716e543d97 785 readBuf(RegFifo, LMIC.frame, LMIC.dataLen);
dudmuck 0:f2716e543d97 786 // read rx quality parameters
dudmuck 0:f2716e543d97 787 LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4
dudmuck 0:f2716e543d97 788 LMIC.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63)
dudmuck 0:f2716e543d97 789 } else if( flags & IRQ_LORA_RXTOUT_MASK ) {
dudmuck 0:f2716e543d97 790 // indicate timeout
dudmuck 0:f2716e543d97 791 LMIC.dataLen = 0;
dudmuck 0:f2716e543d97 792 }
dudmuck 0:f2716e543d97 793 // mask all radio IRQs
dudmuck 0:f2716e543d97 794 writeReg(LORARegIrqFlagsMask, 0xFF);
dudmuck 0:f2716e543d97 795 // clear radio IRQ flags
dudmuck 0:f2716e543d97 796 writeReg(LORARegIrqFlags, 0xFF);
dudmuck 0:f2716e543d97 797 } else { // FSK modem
dudmuck 0:f2716e543d97 798 u1_t flags1 = readReg(FSKRegIrqFlags1);
dudmuck 0:f2716e543d97 799 u1_t flags2 = readReg(FSKRegIrqFlags2);
dudmuck 0:f2716e543d97 800 if( flags2 & IRQ_FSK2_PACKETSENT_MASK ) {
dudmuck 0:f2716e543d97 801 // save exact tx time
dudmuck 0:f2716e543d97 802 LMIC.txend = now;
dudmuck 0:f2716e543d97 803 } else if( flags2 & IRQ_FSK2_PAYLOADREADY_MASK ) {
dudmuck 0:f2716e543d97 804 // save exact rx time
dudmuck 0:f2716e543d97 805 LMIC.rxtime = now;
dudmuck 0:f2716e543d97 806 // read the PDU and inform the MAC that we received something
dudmuck 0:f2716e543d97 807 LMIC.dataLen = readReg(FSKRegPayloadLength);
dudmuck 0:f2716e543d97 808 // now read the FIFO
dudmuck 0:f2716e543d97 809 readBuf(RegFifo, LMIC.frame, LMIC.dataLen);
dudmuck 0:f2716e543d97 810 // read rx quality parameters
dudmuck 0:f2716e543d97 811 LMIC.snr = 0; // determine snr
dudmuck 0:f2716e543d97 812 LMIC.rssi = 0; // determine rssi
dudmuck 0:f2716e543d97 813 } else if( flags1 & IRQ_FSK1_TIMEOUT_MASK ) {
dudmuck 0:f2716e543d97 814 // indicate timeout
dudmuck 0:f2716e543d97 815 LMIC.dataLen = 0;
dudmuck 0:f2716e543d97 816 } else {
dudmuck 0:f2716e543d97 817 while(1);
dudmuck 0:f2716e543d97 818 }
dudmuck 0:f2716e543d97 819 }
dudmuck 0:f2716e543d97 820 // go from stanby to sleep
dudmuck 0:f2716e543d97 821 opmode(OPMODE_SLEEP);
dudmuck 0:f2716e543d97 822 // run os job (use preset func ptr)
dudmuck 0:f2716e543d97 823 os_setCallback(&LMIC.osjob, LMIC.osjob.func);
dudmuck 0:f2716e543d97 824 }
dudmuck 0:f2716e543d97 825
dudmuck 0:f2716e543d97 826 void os_radio (u1_t mode) {
dudmuck 0:f2716e543d97 827 hal_disableIRQs();
dudmuck 0:f2716e543d97 828 switch (mode) {
dudmuck 0:f2716e543d97 829 case RADIO_RST:
dudmuck 0:f2716e543d97 830 // put radio to sleep
dudmuck 0:f2716e543d97 831 opmode(OPMODE_SLEEP);
dudmuck 0:f2716e543d97 832 break;
dudmuck 0:f2716e543d97 833
dudmuck 0:f2716e543d97 834 case RADIO_TX:
dudmuck 0:f2716e543d97 835 // transmit frame now
dudmuck 0:f2716e543d97 836 starttx(); // buf=LMIC.frame, len=LMIC.dataLen
dudmuck 0:f2716e543d97 837 break;
dudmuck 0:f2716e543d97 838
dudmuck 0:f2716e543d97 839 case RADIO_RX:
dudmuck 0:f2716e543d97 840 // receive frame now (exactly at rxtime)
dudmuck 0:f2716e543d97 841 startrx(RXMODE_SINGLE); // buf=LMIC.frame, time=LMIC.rxtime, timeout=LMIC.rxsyms
dudmuck 0:f2716e543d97 842 break;
dudmuck 0:f2716e543d97 843
dudmuck 0:f2716e543d97 844 case RADIO_RXON:
dudmuck 0:f2716e543d97 845 // start scanning for beacon now
dudmuck 0:f2716e543d97 846 startrx(RXMODE_SCAN); // buf=LMIC.frame
dudmuck 0:f2716e543d97 847 break;
dudmuck 0:f2716e543d97 848 }
dudmuck 0:f2716e543d97 849 hal_enableIRQs();
dudmuck 0:f2716e543d97 850 }