Fix ADR channel mask handling
Fork of lmic_MOTE_L152RC by
radio.cpp@9:83ae7f34e88c, 2015-11-16 (annotated)
- 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?
User | Revision | Line number | New 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 | } |