LMIC for MOTE_L152RC
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_HYBRID | 125KHz | 500KHz |
---|---|---|
defined value | channels | channel |
0 | 0 to 7 | 64 |
1 | 8 to 15 | 65 |
2 | 16 to 23 | 66 |
3 | 24 to 31 | 67 |
4 | 32 to 39 | 68 |
5 | 40 to 47 | 69 |
6 | 48 to 55 | 70 |
7 | 56 to 63 | 71 |
undef | 0 to 63 | 64 to 71 |
radio.cpp@0:f2716e543d97, 2015-06-02 (annotated)
- 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?
User | Revision | Line number | New contents of line |
---|---|---|---|
dudmuck | 0:f2716e543d97 | 1 | /******************************************************************************* |
dudmuck | 0:f2716e543d97 | 2 | * Copyright (c) 2014-2015 IBM Corporation. |
dudmuck | 0:f2716e543d97 | 3 | * All rights reserved. This program and the accompanying materials |
dudmuck | 0:f2716e543d97 | 4 | * are made available under the terms of the Eclipse Public License v1.0 |
dudmuck | 0:f2716e543d97 | 5 | * which accompanies this distribution, and is available at |
dudmuck | 0:f2716e543d97 | 6 | * http://www.eclipse.org/legal/epl-v10.html |
dudmuck | 0:f2716e543d97 | 7 | * |
dudmuck | 0:f2716e543d97 | 8 | * Contributors: |
dudmuck | 0:f2716e543d97 | 9 | * IBM Zurich Research Lab - initial API, implementation and documentation |
dudmuck | 0:f2716e543d97 | 10 | *******************************************************************************/ |
dudmuck | 0:f2716e543d97 | 11 | |
dudmuck | 0:f2716e543d97 | 12 | #include "lmic.h" |
dudmuck | 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 | } |