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:
Tue Jun 02 19:04:29 2015 +0000
Revision:
0:f2716e543d97
Child:
2:edb5d1f3deeb
lmic-v1.5 for MOTE_L152RC

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