LMIC for MOTE_L152RC

Dependents:   lmic_transmit

LoRa WAN in C for NA-mote 72

Currently version 1.5


LoRaWAN network configuration for end-device

The following three pieces of information uniquely identifies end-device to network to allow over-the-air activation. These are stored in the end-device prior to join procedure.

AppEUI

Uniquely identifies application provider of end-device.

Least-significant byte first, 8 bytes. Use LMIC_reverse_memcpy() for AppEUI to keep same byte order as that on lora server.

example C code

static const u1_t APPEUI[8]  = { 0x01, 0x00, 0x01, 0x00, 0x00, 0x0C, 0x25, 0x00 };

This is copied into LMIC by os_getArtEui() callback function in application.

DevEUI

End-device ID, unique to each end-node.

Least-significant byte first, 8 bytes. Use LMIC_reverse_memcpy() for DevEUI to keep same byte order as that on lora server.

example C code

static const u1_t DEVEUI[8]  = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x0C, 0x25, 0x00 }; 

This is copied into LMIC by os_getDevEui() callback function in application.

AppKey (aka DevKey)

128-bit (16byte) AES key.

example C code

static const u1_t DEVKEY[16] = { 0xe4, 0x72, 0x71, 0xc5, 0xf5, 0x30, 0xa9, 0x9f, 0xcf, 0xc4, 0x0e, 0xab, 0xea, 0xd7, 0x19, 0x42 };

This is copied into LMIC by os_getDevKey() callback function in application.

Using over-the air activation, the end-device (LMIC) performs a join procedure every time it starts for first time, or has lost session context information. When join procedure has successfully completed, the end-device will have a network session key (NwkSKey) and an application session key (AppSKey), which are used for encryption and message integrity check.


configuration with http://us01-iot.semtech.com/

  • log in to server
  • click on Applications
  • find your application and click it
  • go to configure motes
  • to create a mote, you may enter a new DevEUI
    • you may copy-paste the 16byte application key from an already existing mote, if you desire.

Information

DevEUI is entered in reverse order into C-code from that shown on server (unique device ID).

AppEUI is entered in reverse order into C-code from that shown on server.

AppEUI is equivalent to "Application"

transmit power limits

FCC Part 15 rules permit one watt of transmit power when more than 50 channels are used. When received by a 64-channel gateway, the maximum power may be used.

However, if end-device is sending to a 8-channel gateway (single SX1301), the maximum transmit power permitted is +20dBm.

To configure LMIC for use with 8-channel gateway, CHNL_HYBRID should be defined in in config.h, and should be undefined for use with 64-channel gateway.

CHNL_HYBRID125KHz500KHz
defined valuechannelschannel
00 to 764
18 to 1565
216 to 2366
324 to 3167
432 to 3968
540 to 4769
648 to 5570
756 to 6371
undef0 to 6364 to 71
Committer:
dudmuck
Date:
Thu Jun 04 20:00:55 2015 +0000
Revision:
2:edb5d1f3deeb
Parent:
0:f2716e543d97
Child:
3:d87012f45bf6
add full TX power for NA-mote

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 2:edb5d1f3deeb 13 #include "debug.h" // wbr
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 0:f2716e543d97 108 #define LORARegTimingInvert 0x3B
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 0:f2716e543d97 231 #define MAP_DIO2_LORA_NOP 0xC0 // ----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 0:f2716e543d97 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 0:f2716e543d97 400
dudmuck 0:f2716e543d97 401
dudmuck 0:f2716e543d97 402 static void configPower () {
dudmuck 0:f2716e543d97 403 #ifdef CFG_sx1276_radio
dudmuck 0:f2716e543d97 404 // no boost used for now
dudmuck 0:f2716e543d97 405 s1_t pw = (s1_t)LMIC.txpow;
dudmuck 0:f2716e543d97 406 if(pw >= 17) {
dudmuck 0:f2716e543d97 407 pw = 15;
dudmuck 0:f2716e543d97 408 } else if(pw < 2) {
dudmuck 0:f2716e543d97 409 pw = 2;
dudmuck 0:f2716e543d97 410 }
dudmuck 0:f2716e543d97 411 // check board type for BOOST pin
dudmuck 0:f2716e543d97 412 writeReg(RegPaConfig, (u1_t)(0x80|(pw&0xf)));
dudmuck 0:f2716e543d97 413 writeReg(RegPaDac, readReg(RegPaDac)|0x4);
dudmuck 0:f2716e543d97 414
dudmuck 0:f2716e543d97 415 #elif defined(CFG_sx1272_radio)
dudmuck 0:f2716e543d97 416 // set PA config (2-17 dBm using PA_BOOST)
dudmuck 0:f2716e543d97 417 s1_t pw = (s1_t)LMIC.txpow;
dudmuck 2:edb5d1f3deeb 418 /*if(pw > 17) {
dudmuck 0:f2716e543d97 419 pw = 17;
dudmuck 0:f2716e543d97 420 } else if(pw < 2) {
dudmuck 0:f2716e543d97 421 pw = 2;
dudmuck 2:edb5d1f3deeb 422 }*/
dudmuck 2:edb5d1f3deeb 423 /* NA-mote TX power config: */
dudmuck 2:edb5d1f3deeb 424 if (pw > 23) {
dudmuck 2:edb5d1f3deeb 425 // use RFO with external amplifier
dudmuck 2:edb5d1f3deeb 426 PaSelect = 0x00; // use RFO
dudmuck 2:edb5d1f3deeb 427 writeReg(RegPaConfig, (u1_t)(PaSelect|(pw-25)));
dudmuck 2:edb5d1f3deeb 428 } else {
dudmuck 2:edb5d1f3deeb 429 // use PA_BOOST directo to antenna
dudmuck 2:edb5d1f3deeb 430 PaSelect = 0x80; // use PA_BOOST
dudmuck 2:edb5d1f3deeb 431 if (pw > 17)
dudmuck 2:edb5d1f3deeb 432 pw = 17;
dudmuck 2:edb5d1f3deeb 433 writeReg(RegPaConfig, (u1_t)(PaSelect|(pw-2)));
dudmuck 0:f2716e543d97 434 }
dudmuck 0:f2716e543d97 435
dudmuck 2:edb5d1f3deeb 436
dudmuck 0:f2716e543d97 437 #else
dudmuck 0:f2716e543d97 438 #error Missing CFG_sx1272_radio/CFG_sx1276_radio
dudmuck 0:f2716e543d97 439 #endif /* CFG_sx1272_radio */
dudmuck 0:f2716e543d97 440 }
dudmuck 0:f2716e543d97 441
dudmuck 0:f2716e543d97 442 static void txfsk () {
dudmuck 0:f2716e543d97 443 // select FSK modem (from sleep mode)
dudmuck 0:f2716e543d97 444 writeReg(RegOpMode, 0x10); // FSK, BT=0.5
dudmuck 0:f2716e543d97 445 ASSERT(readReg(RegOpMode) == 0x10);
dudmuck 0:f2716e543d97 446 // enter standby mode (required for FIFO loading))
dudmuck 0:f2716e543d97 447 opmode(OPMODE_STANDBY);
dudmuck 0:f2716e543d97 448 // set bitrate
dudmuck 0:f2716e543d97 449 writeReg(FSKRegBitrateMsb, 0x02); // 50kbps
dudmuck 0:f2716e543d97 450 writeReg(FSKRegBitrateLsb, 0x80);
dudmuck 0:f2716e543d97 451 // set frequency deviation
dudmuck 0:f2716e543d97 452 writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz
dudmuck 0:f2716e543d97 453 writeReg(FSKRegFdevLsb, 0x99);
dudmuck 0:f2716e543d97 454 // frame and packet handler settings
dudmuck 0:f2716e543d97 455 writeReg(FSKRegPreambleMsb, 0x00);
dudmuck 0:f2716e543d97 456 writeReg(FSKRegPreambleLsb, 0x05);
dudmuck 0:f2716e543d97 457 writeReg(FSKRegSyncConfig, 0x12);
dudmuck 0:f2716e543d97 458 writeReg(FSKRegPacketConfig1, 0xD0);
dudmuck 0:f2716e543d97 459 writeReg(FSKRegPacketConfig2, 0x40);
dudmuck 0:f2716e543d97 460 writeReg(FSKRegSyncValue1, 0xC1);
dudmuck 0:f2716e543d97 461 writeReg(FSKRegSyncValue2, 0x94);
dudmuck 0:f2716e543d97 462 writeReg(FSKRegSyncValue3, 0xC1);
dudmuck 0:f2716e543d97 463 // configure frequency
dudmuck 0:f2716e543d97 464 configChannel();
dudmuck 0:f2716e543d97 465 // configure output power
dudmuck 0:f2716e543d97 466 configPower();
dudmuck 0:f2716e543d97 467
dudmuck 0:f2716e543d97 468 // set the IRQ mapping DIO0=PacketSent DIO1=NOP DIO2=NOP
dudmuck 0:f2716e543d97 469 writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TXNOP);
dudmuck 0:f2716e543d97 470
dudmuck 0:f2716e543d97 471 // initialize the payload size and address pointers
dudmuck 0:f2716e543d97 472 writeReg(FSKRegPayloadLength, LMIC.dataLen+1); // (insert length byte into payload))
dudmuck 0:f2716e543d97 473
dudmuck 0:f2716e543d97 474 // download length byte and buffer to the radio FIFO
dudmuck 0:f2716e543d97 475 writeReg(RegFifo, LMIC.dataLen);
dudmuck 0:f2716e543d97 476 writeBuf(RegFifo, LMIC.frame, LMIC.dataLen);
dudmuck 0:f2716e543d97 477
dudmuck 0:f2716e543d97 478 // enable antenna switch for TX
dudmuck 2:edb5d1f3deeb 479 //hal_pin_rxtx(1); usint hal_opmode
dudmuck 0:f2716e543d97 480
dudmuck 0:f2716e543d97 481 // now we actually start the transmission
dudmuck 0:f2716e543d97 482 opmode(OPMODE_TX);
dudmuck 0:f2716e543d97 483 }
dudmuck 0:f2716e543d97 484
dudmuck 0:f2716e543d97 485 static void txlora () {
dudmuck 0:f2716e543d97 486 // select LoRa modem (from sleep mode)
dudmuck 0:f2716e543d97 487 //writeReg(RegOpMode, OPMODE_LORA);
dudmuck 0:f2716e543d97 488 opmodeLora();
dudmuck 0:f2716e543d97 489 ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0);
dudmuck 0:f2716e543d97 490
dudmuck 0:f2716e543d97 491 // enter standby mode (required for FIFO loading))
dudmuck 0:f2716e543d97 492 opmode(OPMODE_STANDBY);
dudmuck 0:f2716e543d97 493 // configure LoRa modem (cfg1, cfg2)
dudmuck 0:f2716e543d97 494 configLoraModem();
dudmuck 0:f2716e543d97 495 // configure frequency
dudmuck 0:f2716e543d97 496 configChannel();
dudmuck 0:f2716e543d97 497 // configure output power
dudmuck 0:f2716e543d97 498 writeReg(RegPaRamp, (readReg(RegPaRamp) & 0xF0) | 0x08); // set PA ramp-up time 50 uSec
dudmuck 0:f2716e543d97 499 configPower();
dudmuck 0:f2716e543d97 500 // set sync word
dudmuck 0:f2716e543d97 501 writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE);
dudmuck 0:f2716e543d97 502
dudmuck 0:f2716e543d97 503 // set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP
dudmuck 0:f2716e543d97 504 writeReg(RegDioMapping1, MAP_DIO0_LORA_TXDONE|MAP_DIO1_LORA_NOP|MAP_DIO2_LORA_NOP);
dudmuck 0:f2716e543d97 505 // clear all radio IRQ flags
dudmuck 0:f2716e543d97 506 writeReg(LORARegIrqFlags, 0xFF);
dudmuck 0:f2716e543d97 507 // mask all IRQs but TxDone
dudmuck 0:f2716e543d97 508 writeReg(LORARegIrqFlagsMask, ~IRQ_LORA_TXDONE_MASK);
dudmuck 0:f2716e543d97 509
dudmuck 0:f2716e543d97 510 // initialize the payload size and address pointers
dudmuck 0:f2716e543d97 511 writeReg(LORARegFifoTxBaseAddr, 0x00);
dudmuck 0:f2716e543d97 512 writeReg(LORARegFifoAddrPtr, 0x00);
dudmuck 0:f2716e543d97 513 writeReg(LORARegPayloadLength, LMIC.dataLen);
dudmuck 0:f2716e543d97 514
dudmuck 0:f2716e543d97 515 // download buffer to the radio FIFO
dudmuck 0:f2716e543d97 516 writeBuf(RegFifo, LMIC.frame, LMIC.dataLen);
dudmuck 0:f2716e543d97 517
dudmuck 0:f2716e543d97 518 // enable antenna switch for TX
dudmuck 2:edb5d1f3deeb 519 //hal_pin_rxtx(1); using hal_opmode
dudmuck 0:f2716e543d97 520
dudmuck 0:f2716e543d97 521 // now we actually start the transmission
dudmuck 0:f2716e543d97 522 opmode(OPMODE_TX);
dudmuck 0:f2716e543d97 523 }
dudmuck 0:f2716e543d97 524
dudmuck 0:f2716e543d97 525 // start transmitter (buf=LMIC.frame, len=LMIC.dataLen)
dudmuck 0:f2716e543d97 526 static void starttx () {
dudmuck 0:f2716e543d97 527 ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP );
dudmuck 0:f2716e543d97 528 if(getSf(LMIC.rps) == FSK) { // FSK modem
dudmuck 0:f2716e543d97 529 txfsk();
dudmuck 0:f2716e543d97 530 } else { // LoRa modem
dudmuck 0:f2716e543d97 531 txlora();
dudmuck 0:f2716e543d97 532 }
dudmuck 0:f2716e543d97 533 // the radio will go back to STANDBY mode as soon as the TX is finished
dudmuck 0:f2716e543d97 534 // the corresponding IRQ will inform us about completion.
dudmuck 0:f2716e543d97 535 }
dudmuck 0:f2716e543d97 536
dudmuck 0:f2716e543d97 537 enum { RXMODE_SINGLE, RXMODE_SCAN, RXMODE_RSSI };
dudmuck 0:f2716e543d97 538
dudmuck 0:f2716e543d97 539 static const u1_t rxlorairqmask[] = {
dudmuck 0:f2716e543d97 540 [RXMODE_SINGLE] = IRQ_LORA_RXDONE_MASK|IRQ_LORA_RXTOUT_MASK,
dudmuck 0:f2716e543d97 541 [RXMODE_SCAN] = IRQ_LORA_RXDONE_MASK,
dudmuck 0:f2716e543d97 542 [RXMODE_RSSI] = 0x00,
dudmuck 0:f2716e543d97 543 };
dudmuck 0:f2716e543d97 544
dudmuck 0:f2716e543d97 545 // start LoRa receiver (time=LMIC.rxtime, timeout=LMIC.rxsyms, result=LMIC.frame[LMIC.dataLen])
dudmuck 0:f2716e543d97 546 static void rxlora (u1_t rxmode) {
dudmuck 0:f2716e543d97 547 // select LoRa modem (from sleep mode)
dudmuck 0:f2716e543d97 548 opmodeLora();
dudmuck 0:f2716e543d97 549 ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0);
dudmuck 0:f2716e543d97 550 // enter standby mode (warm up))
dudmuck 0:f2716e543d97 551 opmode(OPMODE_STANDBY);
dudmuck 0:f2716e543d97 552 // don't use MAC settings at startup
dudmuck 0:f2716e543d97 553 if(rxmode == RXMODE_RSSI) { // use fixed settings for rssi scan
dudmuck 0:f2716e543d97 554 writeReg(LORARegModemConfig1, RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1);
dudmuck 0:f2716e543d97 555 writeReg(LORARegModemConfig2, RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2);
dudmuck 0:f2716e543d97 556 } else { // single or continuous rx mode
dudmuck 0:f2716e543d97 557 // configure LoRa modem (cfg1, cfg2)
dudmuck 0:f2716e543d97 558 configLoraModem();
dudmuck 0:f2716e543d97 559 // configure frequency
dudmuck 0:f2716e543d97 560 configChannel();
dudmuck 0:f2716e543d97 561 }
dudmuck 0:f2716e543d97 562 // set LNA gain
dudmuck 0:f2716e543d97 563 writeReg(RegLna, LNA_RX_GAIN);
dudmuck 0:f2716e543d97 564 // set max payload size
dudmuck 0:f2716e543d97 565 writeReg(LORARegPayloadMaxLength, 64);
dudmuck 0:f2716e543d97 566 // use inverted I/Q signal (prevent mote-to-mote communication)
dudmuck 0:f2716e543d97 567 writeReg(LORARegInvertIQ, readReg(LORARegInvertIQ)|(1<<6));
dudmuck 0:f2716e543d97 568 // set symbol timeout (for single rx)
dudmuck 0:f2716e543d97 569 writeReg(LORARegSymbTimeoutLsb, LMIC.rxsyms);
dudmuck 0:f2716e543d97 570 // set sync word
dudmuck 0:f2716e543d97 571 writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE);
dudmuck 0:f2716e543d97 572
dudmuck 0:f2716e543d97 573 // configure DIO mapping DIO0=RxDone DIO1=RxTout DIO2=NOP
dudmuck 0:f2716e543d97 574 writeReg(RegDioMapping1, MAP_DIO0_LORA_RXDONE|MAP_DIO1_LORA_RXTOUT|MAP_DIO2_LORA_NOP);
dudmuck 0:f2716e543d97 575 // clear all radio IRQ flags
dudmuck 0:f2716e543d97 576 writeReg(LORARegIrqFlags, 0xFF);
dudmuck 0:f2716e543d97 577 // enable required radio IRQs
dudmuck 0:f2716e543d97 578 writeReg(LORARegIrqFlagsMask, ~rxlorairqmask[rxmode]);
dudmuck 0:f2716e543d97 579
dudmuck 0:f2716e543d97 580 // enable antenna switch for RX
dudmuck 2:edb5d1f3deeb 581 //hal_pin_rxtx(0); using hal_opmode
dudmuck 0:f2716e543d97 582
dudmuck 0:f2716e543d97 583 // now instruct the radio to receive
dudmuck 0:f2716e543d97 584 if (rxmode == RXMODE_SINGLE) { // single rx
dudmuck 0:f2716e543d97 585 hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
dudmuck 0:f2716e543d97 586 opmode(OPMODE_RX_SINGLE);
dudmuck 0:f2716e543d97 587 } else { // continous rx (scan or rssi)
dudmuck 0:f2716e543d97 588 opmode(OPMODE_RX);
dudmuck 0:f2716e543d97 589 }
dudmuck 0:f2716e543d97 590 }
dudmuck 0:f2716e543d97 591
dudmuck 0:f2716e543d97 592 static void rxfsk (u1_t rxmode) {
dudmuck 0:f2716e543d97 593 // only single rx (no continuous scanning, no noise sampling)
dudmuck 0:f2716e543d97 594 ASSERT( rxmode == RXMODE_SINGLE );
dudmuck 0:f2716e543d97 595 // select FSK modem (from sleep mode)
dudmuck 0:f2716e543d97 596 //writeReg(RegOpMode, 0x00); // (not LoRa)
dudmuck 0:f2716e543d97 597 opmodeFSK();
dudmuck 0:f2716e543d97 598 ASSERT((readReg(RegOpMode) & OPMODE_LORA) == 0);
dudmuck 0:f2716e543d97 599 // enter standby mode (warm up))
dudmuck 0:f2716e543d97 600 opmode(OPMODE_STANDBY);
dudmuck 0:f2716e543d97 601 // configure frequency
dudmuck 0:f2716e543d97 602 configChannel();
dudmuck 0:f2716e543d97 603 // set LNA gain
dudmuck 0:f2716e543d97 604 //writeReg(RegLna, 0x20|0x03); // max gain, boost enable
dudmuck 0:f2716e543d97 605 writeReg(RegLna, LNA_RX_GAIN);
dudmuck 0:f2716e543d97 606 // configure receiver
dudmuck 0:f2716e543d97 607 writeReg(FSKRegRxConfig, 0x1E); // AFC auto, AGC, trigger on preamble?!?
dudmuck 0:f2716e543d97 608 // set receiver bandwidth
dudmuck 0:f2716e543d97 609 writeReg(FSKRegRxBw, 0x0B); // 50kHz SSb
dudmuck 0:f2716e543d97 610 // set AFC bandwidth
dudmuck 0:f2716e543d97 611 writeReg(FSKRegAfcBw, 0x12); // 83.3kHz SSB
dudmuck 0:f2716e543d97 612 // set preamble detection
dudmuck 0:f2716e543d97 613 writeReg(FSKRegPreambleDetect, 0xAA); // enable, 2 bytes, 10 chip errors
dudmuck 0:f2716e543d97 614 // set sync config
dudmuck 0:f2716e543d97 615 writeReg(FSKRegSyncConfig, 0x12); // no auto restart, preamble 0xAA, enable, fill FIFO, 3 bytes sync
dudmuck 0:f2716e543d97 616 // set packet config
dudmuck 0:f2716e543d97 617 writeReg(FSKRegPacketConfig1, 0xD8); // var-length, whitening, crc, no auto-clear, no adr filter
dudmuck 0:f2716e543d97 618 writeReg(FSKRegPacketConfig2, 0x40); // packet mode
dudmuck 0:f2716e543d97 619 // set sync value
dudmuck 0:f2716e543d97 620 writeReg(FSKRegSyncValue1, 0xC1);
dudmuck 0:f2716e543d97 621 writeReg(FSKRegSyncValue2, 0x94);
dudmuck 0:f2716e543d97 622 writeReg(FSKRegSyncValue3, 0xC1);
dudmuck 0:f2716e543d97 623 // set preamble timeout
dudmuck 0:f2716e543d97 624 writeReg(FSKRegRxTimeout2, 0xFF);//(LMIC.rxsyms+1)/2);
dudmuck 0:f2716e543d97 625 // set bitrate
dudmuck 0:f2716e543d97 626 writeReg(FSKRegBitrateMsb, 0x02); // 50kbps
dudmuck 0:f2716e543d97 627 writeReg(FSKRegBitrateLsb, 0x80);
dudmuck 0:f2716e543d97 628 // set frequency deviation
dudmuck 0:f2716e543d97 629 writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz
dudmuck 0:f2716e543d97 630 writeReg(FSKRegFdevLsb, 0x99);
dudmuck 0:f2716e543d97 631
dudmuck 0:f2716e543d97 632 // configure DIO mapping DIO0=PayloadReady DIO1=NOP DIO2=TimeOut
dudmuck 0:f2716e543d97 633 writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TIMEOUT);
dudmuck 0:f2716e543d97 634
dudmuck 0:f2716e543d97 635 // enable antenna switch for RX
dudmuck 2:edb5d1f3deeb 636 //hal_pin_rxtx(0); using hal_opmode
dudmuck 0:f2716e543d97 637
dudmuck 0:f2716e543d97 638 // now instruct the radio to receive
dudmuck 0:f2716e543d97 639 hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
dudmuck 0:f2716e543d97 640 opmode(OPMODE_RX); // no single rx mode available in FSK
dudmuck 0:f2716e543d97 641 }
dudmuck 0:f2716e543d97 642
dudmuck 0:f2716e543d97 643 static void startrx (u1_t rxmode) {
dudmuck 0:f2716e543d97 644 ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP );
dudmuck 0:f2716e543d97 645 if(getSf(LMIC.rps) == FSK) { // FSK modem
dudmuck 0:f2716e543d97 646 rxfsk(rxmode);
dudmuck 0:f2716e543d97 647 } else { // LoRa modem
dudmuck 0:f2716e543d97 648 rxlora(rxmode);
dudmuck 0:f2716e543d97 649 }
dudmuck 0:f2716e543d97 650 // the radio will go back to STANDBY mode as soon as the RX is finished
dudmuck 0:f2716e543d97 651 // or timed out, and the corresponding IRQ will inform us about completion.
dudmuck 0:f2716e543d97 652 }
dudmuck 0:f2716e543d97 653
dudmuck 0:f2716e543d97 654 // get random seed from wideband noise rssi
dudmuck 0:f2716e543d97 655 void radio_init () {
dudmuck 0:f2716e543d97 656 hal_disableIRQs();
dudmuck 0:f2716e543d97 657
dudmuck 0:f2716e543d97 658 // manually reset radio
dudmuck 0:f2716e543d97 659 #ifdef CFG_sx1276_radio
dudmuck 0:f2716e543d97 660 hal_pin_rst(0); // drive RST pin low
dudmuck 0:f2716e543d97 661 #else
dudmuck 0:f2716e543d97 662 hal_pin_rst(1); // drive RST pin high
dudmuck 0:f2716e543d97 663 #endif
dudmuck 0:f2716e543d97 664 hal_waitUntil(os_getTime()+ms2osticks(1)); // wait >100us
dudmuck 0:f2716e543d97 665 hal_pin_rst(2); // configure RST pin floating!
dudmuck 0:f2716e543d97 666 hal_waitUntil(os_getTime()+ms2osticks(5)); // wait 5ms
dudmuck 0:f2716e543d97 667
dudmuck 0:f2716e543d97 668 opmode(OPMODE_SLEEP);
dudmuck 0:f2716e543d97 669
dudmuck 0:f2716e543d97 670 // some sanity checks, e.g., read version number
dudmuck 0:f2716e543d97 671 u1_t v = readReg(RegVersion);
dudmuck 0:f2716e543d97 672 #ifdef CFG_sx1276_radio
dudmuck 0:f2716e543d97 673 ASSERT(v == 0x12 );
dudmuck 0:f2716e543d97 674 #elif defined(CFG_sx1272_radio)
dudmuck 0:f2716e543d97 675 ASSERT(v == 0x22);
dudmuck 0:f2716e543d97 676 #else
dudmuck 0:f2716e543d97 677 #error Missing CFG_sx1272_radio/CFG_sx1276_radio
dudmuck 0:f2716e543d97 678 #endif
dudmuck 0:f2716e543d97 679 // seed 15-byte randomness via noise rssi
dudmuck 0:f2716e543d97 680 rxlora(RXMODE_RSSI);
dudmuck 0:f2716e543d97 681 while( (readReg(RegOpMode) & OPMODE_MASK) != OPMODE_RX ); // continuous rx
dudmuck 0:f2716e543d97 682 for(int i=1; i<16; i++) {
dudmuck 0:f2716e543d97 683 for(int j=0; j<8; j++) {
dudmuck 0:f2716e543d97 684 u1_t b; // wait for two non-identical subsequent least-significant bits
dudmuck 0:f2716e543d97 685 while( (b = readReg(LORARegRssiWideband) & 0x01) == (readReg(LORARegRssiWideband) & 0x01) );
dudmuck 0:f2716e543d97 686 randbuf[i] = (randbuf[i] << 1) | b;
dudmuck 0:f2716e543d97 687 }
dudmuck 0:f2716e543d97 688 }
dudmuck 0:f2716e543d97 689 randbuf[0] = 16; // set initial index
dudmuck 0:f2716e543d97 690
dudmuck 0:f2716e543d97 691 #ifdef CFG_sx1276mb1_board
dudmuck 0:f2716e543d97 692 // chain calibration
dudmuck 0:f2716e543d97 693 writeReg(RegPaConfig, 0);
dudmuck 0:f2716e543d97 694
dudmuck 0:f2716e543d97 695 // Launch Rx chain calibration for LF band
dudmuck 0:f2716e543d97 696 writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START);
dudmuck 0:f2716e543d97 697 while((readReg(FSKRegImageCal)&RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING){ ; }
dudmuck 0:f2716e543d97 698
dudmuck 0:f2716e543d97 699 // Sets a Frequency in HF band
dudmuck 0:f2716e543d97 700 u4_t frf = 868000000;
dudmuck 0:f2716e543d97 701 writeReg(RegFrfMsb, (u1_t)(frf>>16));
dudmuck 0:f2716e543d97 702 writeReg(RegFrfMid, (u1_t)(frf>> 8));
dudmuck 0:f2716e543d97 703 writeReg(RegFrfLsb, (u1_t)(frf>> 0));
dudmuck 0:f2716e543d97 704
dudmuck 0:f2716e543d97 705 // Launch Rx chain calibration for HF band
dudmuck 0:f2716e543d97 706 writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START);
dudmuck 0:f2716e543d97 707 while((readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING) { ; }
dudmuck 0:f2716e543d97 708 #endif /* CFG_sx1276mb1_board */
dudmuck 0:f2716e543d97 709
dudmuck 0:f2716e543d97 710 /* SF12/500KHz RX improvement (0x1d/0x19 choice): must match setting of LORARegInvertIQ */
dudmuck 0:f2716e543d97 711 writeReg(LORARegTimingInvert, 0x19);
dudmuck 0:f2716e543d97 712
dudmuck 0:f2716e543d97 713 opmode(OPMODE_SLEEP);
dudmuck 0:f2716e543d97 714
dudmuck 0:f2716e543d97 715 hal_enableIRQs();
dudmuck 0:f2716e543d97 716 }
dudmuck 0:f2716e543d97 717
dudmuck 0:f2716e543d97 718 // return next random byte derived from seed buffer
dudmuck 0:f2716e543d97 719 // (buf[0] holds index of next byte to be returned)
dudmuck 0:f2716e543d97 720 u1_t radio_rand1 () {
dudmuck 0:f2716e543d97 721 u1_t i = randbuf[0];
dudmuck 0:f2716e543d97 722 ASSERT( i != 0 );
dudmuck 0:f2716e543d97 723 if( i==16 ) {
dudmuck 0:f2716e543d97 724 os_aes(AES_ENC, randbuf, 16); // encrypt seed with any key
dudmuck 0:f2716e543d97 725 i = 0;
dudmuck 0:f2716e543d97 726 }
dudmuck 0:f2716e543d97 727 u1_t v = randbuf[i++];
dudmuck 0:f2716e543d97 728 randbuf[0] = i;
dudmuck 0:f2716e543d97 729 return v;
dudmuck 0:f2716e543d97 730 }
dudmuck 0:f2716e543d97 731
dudmuck 0:f2716e543d97 732 u1_t radio_rssi () {
dudmuck 0:f2716e543d97 733 hal_disableIRQs();
dudmuck 0:f2716e543d97 734 u1_t r = readReg(LORARegRssiValue);
dudmuck 0:f2716e543d97 735 hal_enableIRQs();
dudmuck 0:f2716e543d97 736 return r;
dudmuck 0:f2716e543d97 737 }
dudmuck 0:f2716e543d97 738
dudmuck 0:f2716e543d97 739 static const u2_t LORA_RXDONE_FIXUP[] = {
dudmuck 0:f2716e543d97 740 [FSK] = us2osticks(0), // ( 0 ticks)
dudmuck 0:f2716e543d97 741 [SF7] = us2osticks(0), // ( 0 ticks)
dudmuck 0:f2716e543d97 742 [SF8] = us2osticks(1648), // ( 54 ticks)
dudmuck 0:f2716e543d97 743 [SF9] = us2osticks(3265), // ( 107 ticks)
dudmuck 0:f2716e543d97 744 [SF10] = us2osticks(7049), // ( 231 ticks)
dudmuck 0:f2716e543d97 745 [SF11] = us2osticks(13641), // ( 447 ticks)
dudmuck 0:f2716e543d97 746 [SF12] = us2osticks(31189), // (1022 ticks)
dudmuck 0:f2716e543d97 747 };
dudmuck 0:f2716e543d97 748
dudmuck 0:f2716e543d97 749 // called by hal ext IRQ handler
dudmuck 0:f2716e543d97 750 // (radio goes to stanby mode after tx/rx operations)
dudmuck 0:f2716e543d97 751 void radio_irq_handler (u1_t dio) {
dudmuck 0:f2716e543d97 752 ostime_t now = os_getTime();
dudmuck 0:f2716e543d97 753 if( (readReg(RegOpMode) & OPMODE_LORA) != 0) { // LORA modem
dudmuck 0:f2716e543d97 754 u1_t flags = readReg(LORARegIrqFlags);
dudmuck 0:f2716e543d97 755 if( flags & IRQ_LORA_TXDONE_MASK ) {
dudmuck 0:f2716e543d97 756 // save exact tx time
dudmuck 0:f2716e543d97 757 LMIC.txend = now - us2osticks(43); // TXDONE FIXUP
dudmuck 0:f2716e543d97 758 } else if( flags & IRQ_LORA_RXDONE_MASK ) {
dudmuck 0:f2716e543d97 759 // save exact rx time
dudmuck 0:f2716e543d97 760 if(getBw(LMIC.rps) == BW125) {
dudmuck 0:f2716e543d97 761 now -= LORA_RXDONE_FIXUP[getSf(LMIC.rps)];
dudmuck 0:f2716e543d97 762 }
dudmuck 0:f2716e543d97 763 LMIC.rxtime = now;
dudmuck 0:f2716e543d97 764 // read the PDU and inform the MAC that we received something
dudmuck 0:f2716e543d97 765 LMIC.dataLen = (readReg(LORARegModemConfig1) & SX1272_MC1_IMPLICIT_HEADER_MODE_ON) ?
dudmuck 0:f2716e543d97 766 readReg(LORARegPayloadLength) : readReg(LORARegRxNbBytes);
dudmuck 0:f2716e543d97 767 // set FIFO read address pointer
dudmuck 0:f2716e543d97 768 writeReg(LORARegFifoAddrPtr, readReg(LORARegFifoRxCurrentAddr));
dudmuck 0:f2716e543d97 769 // now read the FIFO
dudmuck 0:f2716e543d97 770 readBuf(RegFifo, LMIC.frame, LMIC.dataLen);
dudmuck 0:f2716e543d97 771 // read rx quality parameters
dudmuck 0:f2716e543d97 772 LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4
dudmuck 0:f2716e543d97 773 LMIC.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63)
dudmuck 0:f2716e543d97 774 } else if( flags & IRQ_LORA_RXTOUT_MASK ) {
dudmuck 0:f2716e543d97 775 // indicate timeout
dudmuck 0:f2716e543d97 776 LMIC.dataLen = 0;
dudmuck 0:f2716e543d97 777 }
dudmuck 0:f2716e543d97 778 // mask all radio IRQs
dudmuck 0:f2716e543d97 779 writeReg(LORARegIrqFlagsMask, 0xFF);
dudmuck 0:f2716e543d97 780 // clear radio IRQ flags
dudmuck 0:f2716e543d97 781 writeReg(LORARegIrqFlags, 0xFF);
dudmuck 0:f2716e543d97 782 } else { // FSK modem
dudmuck 0:f2716e543d97 783 u1_t flags1 = readReg(FSKRegIrqFlags1);
dudmuck 0:f2716e543d97 784 u1_t flags2 = readReg(FSKRegIrqFlags2);
dudmuck 0:f2716e543d97 785 if( flags2 & IRQ_FSK2_PACKETSENT_MASK ) {
dudmuck 0:f2716e543d97 786 // save exact tx time
dudmuck 0:f2716e543d97 787 LMIC.txend = now;
dudmuck 0:f2716e543d97 788 } else if( flags2 & IRQ_FSK2_PAYLOADREADY_MASK ) {
dudmuck 0:f2716e543d97 789 // save exact rx time
dudmuck 0:f2716e543d97 790 LMIC.rxtime = now;
dudmuck 0:f2716e543d97 791 // read the PDU and inform the MAC that we received something
dudmuck 0:f2716e543d97 792 LMIC.dataLen = readReg(FSKRegPayloadLength);
dudmuck 0:f2716e543d97 793 // now read the FIFO
dudmuck 0:f2716e543d97 794 readBuf(RegFifo, LMIC.frame, LMIC.dataLen);
dudmuck 0:f2716e543d97 795 // read rx quality parameters
dudmuck 0:f2716e543d97 796 LMIC.snr = 0; // determine snr
dudmuck 0:f2716e543d97 797 LMIC.rssi = 0; // determine rssi
dudmuck 0:f2716e543d97 798 } else if( flags1 & IRQ_FSK1_TIMEOUT_MASK ) {
dudmuck 0:f2716e543d97 799 // indicate timeout
dudmuck 0:f2716e543d97 800 LMIC.dataLen = 0;
dudmuck 0:f2716e543d97 801 } else {
dudmuck 0:f2716e543d97 802 while(1);
dudmuck 0:f2716e543d97 803 }
dudmuck 0:f2716e543d97 804 }
dudmuck 0:f2716e543d97 805 // go from stanby to sleep
dudmuck 0:f2716e543d97 806 opmode(OPMODE_SLEEP);
dudmuck 0:f2716e543d97 807 // run os job (use preset func ptr)
dudmuck 0:f2716e543d97 808 os_setCallback(&LMIC.osjob, LMIC.osjob.func);
dudmuck 0:f2716e543d97 809 }
dudmuck 0:f2716e543d97 810
dudmuck 0:f2716e543d97 811 void os_radio (u1_t mode) {
dudmuck 0:f2716e543d97 812 hal_disableIRQs();
dudmuck 0:f2716e543d97 813 switch (mode) {
dudmuck 0:f2716e543d97 814 case RADIO_RST:
dudmuck 0:f2716e543d97 815 // put radio to sleep
dudmuck 0:f2716e543d97 816 opmode(OPMODE_SLEEP);
dudmuck 0:f2716e543d97 817 break;
dudmuck 0:f2716e543d97 818
dudmuck 0:f2716e543d97 819 case RADIO_TX:
dudmuck 0:f2716e543d97 820 // transmit frame now
dudmuck 0:f2716e543d97 821 starttx(); // buf=LMIC.frame, len=LMIC.dataLen
dudmuck 0:f2716e543d97 822 break;
dudmuck 0:f2716e543d97 823
dudmuck 0:f2716e543d97 824 case RADIO_RX:
dudmuck 0:f2716e543d97 825 // receive frame now (exactly at rxtime)
dudmuck 0:f2716e543d97 826 startrx(RXMODE_SINGLE); // buf=LMIC.frame, time=LMIC.rxtime, timeout=LMIC.rxsyms
dudmuck 0:f2716e543d97 827 break;
dudmuck 0:f2716e543d97 828
dudmuck 0:f2716e543d97 829 case RADIO_RXON:
dudmuck 0:f2716e543d97 830 // start scanning for beacon now
dudmuck 0:f2716e543d97 831 startrx(RXMODE_SCAN); // buf=LMIC.frame
dudmuck 0:f2716e543d97 832 break;
dudmuck 0:f2716e543d97 833 }
dudmuck 0:f2716e543d97 834 hal_enableIRQs();
dudmuck 0:f2716e543d97 835 }